aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/glk/glulxe/accel.cpp1010
-rw-r--r--engines/glk/glulxe/exec.cpp2015
-rw-r--r--engines/glk/glulxe/float.cpp183
-rw-r--r--engines/glk/glulxe/funcs.cpp506
-rw-r--r--engines/glk/glulxe/gestalt.cpp86
-rw-r--r--engines/glk/glulxe/glkop.cpp2293
-rw-r--r--engines/glk/glulxe/glulxe.cpp34
-rw-r--r--engines/glk/glulxe/glulxe.h124
-rw-r--r--engines/glk/glulxe/glulxe_types.h20
-rw-r--r--engines/glk/glulxe/heap.cpp499
-rw-r--r--engines/glk/glulxe/operand.cpp998
-rw-r--r--engines/glk/glulxe/search.cpp335
-rw-r--r--engines/glk/glulxe/serial.cpp1968
-rw-r--r--engines/glk/glulxe/string.cpp1443
-rw-r--r--engines/glk/glulxe/vm.cpp508
15 files changed, 5972 insertions, 6050 deletions
diff --git a/engines/glk/glulxe/accel.cpp b/engines/glk/glulxe/accel.cpp
index 929c6ab461..1d0b9e5db4 100644
--- a/engines/glk/glulxe/accel.cpp
+++ b/engines/glk/glulxe/accel.cpp
@@ -41,581 +41,623 @@ namespace Glulxe {
#define ARG_IF_GIVEN(argv, argc, ix) ((argc > ix) ? (ARG(argv, argc, ix)) : 0)
acceleration_func Glulxe::accel_find_func(uint index) {
- switch (index) {
- case 0: return nullptr; // 0 always means no acceleration
- case 1: return &Glulxe::func_1_z__region;
- case 2: return &Glulxe::func_2_cp__tab;
- case 3: return &Glulxe::func_3_ra__pr;
- case 4: return &Glulxe::func_4_rl__pr;
- case 5: return &Glulxe::func_5_oc__cl;
- case 6: return &Glulxe::func_6_rv__pr;
- case 7: return &Glulxe::func_7_op__pr;
- case 8: return &Glulxe::func_8_cp__tab;
- case 9: return &Glulxe::func_9_ra__pr;
- case 10: return &Glulxe::func_10_rl__pr;
- case 11: return &Glulxe::func_11_oc__cl;
- case 12: return &Glulxe::func_12_rv__pr;
- case 13: return &Glulxe::func_13_op__pr;
- }
- return nullptr;
+ switch (index) {
+ case 0:
+ return nullptr; // 0 always means no acceleration
+ case 1:
+ return &Glulxe::func_1_z__region;
+ case 2:
+ return &Glulxe::func_2_cp__tab;
+ case 3:
+ return &Glulxe::func_3_ra__pr;
+ case 4:
+ return &Glulxe::func_4_rl__pr;
+ case 5:
+ return &Glulxe::func_5_oc__cl;
+ case 6:
+ return &Glulxe::func_6_rv__pr;
+ case 7:
+ return &Glulxe::func_7_op__pr;
+ case 8:
+ return &Glulxe::func_8_cp__tab;
+ case 9:
+ return &Glulxe::func_9_ra__pr;
+ case 10:
+ return &Glulxe::func_10_rl__pr;
+ case 11:
+ return &Glulxe::func_11_oc__cl;
+ case 12:
+ return &Glulxe::func_12_rv__pr;
+ case 13:
+ return &Glulxe::func_13_op__pr;
+ }
+ return nullptr;
}
acceleration_func Glulxe::accel_get_func(uint addr) {
- int bucknum;
- accelentry_t *ptr;
-
- if (!accelentries)
- return nullptr;
-
- bucknum = (addr % ACCEL_HASH_SIZE);
- for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
- if (ptr->addr == addr)
- return ptr->func;
- }
- return nullptr;
+ int bucknum;
+ accelentry_t *ptr;
+
+ if (!accelentries)
+ return nullptr;
+
+ bucknum = (addr % ACCEL_HASH_SIZE);
+ for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
+ if (ptr->addr == addr)
+ return ptr->func;
+ }
+ return nullptr;
}
void Glulxe::accel_iterate_funcs(void (*func)(uint index, uint addr)) {
- int bucknum;
- accelentry_t *ptr;
-
- if (!accelentries)
- return;
-
- for (bucknum=0; bucknum<ACCEL_HASH_SIZE; bucknum++) {
- for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
- if (ptr->func) {
- func(ptr->index, ptr->addr);
- }
- }
- }
+ int bucknum;
+ accelentry_t *ptr;
+
+ if (!accelentries)
+ return;
+
+ for (bucknum = 0; bucknum < ACCEL_HASH_SIZE; bucknum++) {
+ for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
+ if (ptr->func) {
+ func(ptr->index, ptr->addr);
+ }
+ }
+ }
}
void Glulxe::accel_set_func(uint index, uint addr) {
- int bucknum;
- accelentry_t *ptr;
- int functype;
- acceleration_func new_func = nullptr;
-
- /* Check the Glulx type identifier byte. */
- functype = Mem1(addr);
- if (functype != 0xC0 && functype != 0xC1) {
- fatal_error_i("Attempt to accelerate non-function.", addr);
- }
-
- if (!accelentries) {
- accelentries = (accelentry_t **)glulx_malloc(ACCEL_HASH_SIZE
- * sizeof(accelentry_t *));
- if (!accelentries)
- fatal_error("Cannot malloc acceleration table.");
- for (bucknum=0; bucknum<ACCEL_HASH_SIZE; bucknum++)
- accelentries[bucknum] = nullptr;
- }
-
- new_func = accel_find_func(index);
- /* Might be nullptr, if the index is zero or not recognized. */
-
- bucknum = (addr % ACCEL_HASH_SIZE);
- for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
- if (ptr->addr == addr)
- break;
- }
- if (!ptr) {
- if (!new_func) {
- return; /* no need for a new entry */
- }
- ptr = (accelentry_t *)glulx_malloc(sizeof(accelentry_t));
- if (!ptr)
- fatal_error("Cannot malloc acceleration entry.");
- ptr->addr = addr;
- ptr->index = 0;
- ptr->func = nullptr;
- ptr->next = accelentries[bucknum];
- accelentries[bucknum] = ptr;
- }
-
- ptr->index = index;
- ptr->func = new_func;
+ int bucknum;
+ accelentry_t *ptr;
+ int functype;
+ acceleration_func new_func = nullptr;
+
+ /* Check the Glulx type identifier byte. */
+ functype = Mem1(addr);
+ if (functype != 0xC0 && functype != 0xC1) {
+ fatal_error_i("Attempt to accelerate non-function.", addr);
+ }
+
+ if (!accelentries) {
+ accelentries = (accelentry_t **)glulx_malloc(ACCEL_HASH_SIZE
+ * sizeof(accelentry_t *));
+ if (!accelentries)
+ fatal_error("Cannot malloc acceleration table.");
+ for (bucknum = 0; bucknum < ACCEL_HASH_SIZE; bucknum++)
+ accelentries[bucknum] = nullptr;
+ }
+
+ new_func = accel_find_func(index);
+ /* Might be nullptr, if the index is zero or not recognized. */
+
+ bucknum = (addr % ACCEL_HASH_SIZE);
+ for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
+ if (ptr->addr == addr)
+ break;
+ }
+ if (!ptr) {
+ if (!new_func) {
+ return; /* no need for a new entry */
+ }
+ ptr = (accelentry_t *)glulx_malloc(sizeof(accelentry_t));
+ if (!ptr)
+ fatal_error("Cannot malloc acceleration entry.");
+ ptr->addr = addr;
+ ptr->index = 0;
+ ptr->func = nullptr;
+ ptr->next = accelentries[bucknum];
+ accelentries[bucknum] = ptr;
+ }
+
+ ptr->index = index;
+ ptr->func = new_func;
}
void Glulxe::accel_set_param(uint index, uint val) {
- switch (index) {
- case 0: classes_table = val; break;
- case 1: indiv_prop_start = val; break;
- case 2: class_metaclass = val; break;
- case 3: object_metaclass = val; break;
- case 4: routine_metaclass = val; break;
- case 5: string_metaclass = val; break;
- case 6: self = val; break;
- case 7: num_attr_bytes = val; break;
- case 8: cpv__start = val; break;
- }
+ switch (index) {
+ case 0:
+ classes_table = val;
+ break;
+ case 1:
+ indiv_prop_start = val;
+ break;
+ case 2:
+ class_metaclass = val;
+ break;
+ case 3:
+ object_metaclass = val;
+ break;
+ case 4:
+ routine_metaclass = val;
+ break;
+ case 5:
+ string_metaclass = val;
+ break;
+ case 6:
+ self = val;
+ break;
+ case 7:
+ num_attr_bytes = val;
+ break;
+ case 8:
+ cpv__start = val;
+ break;
+ }
}
uint Glulxe::accel_get_param_count() const {
- return 9;
+ return 9;
}
uint Glulxe::accel_get_param(uint index) const {
- switch (index) {
- case 0: return classes_table;
- case 1: return indiv_prop_start;
- case 2: return class_metaclass;
- case 3: return object_metaclass;
- case 4: return routine_metaclass;
- case 5: return string_metaclass;
- case 6: return self;
- case 7: return num_attr_bytes;
- case 8: return cpv__start;
- default: return 0;
- }
+ switch (index) {
+ case 0:
+ return classes_table;
+ case 1:
+ return indiv_prop_start;
+ case 2:
+ return class_metaclass;
+ case 3:
+ return object_metaclass;
+ case 4:
+ return routine_metaclass;
+ case 5:
+ return string_metaclass;
+ case 6:
+ return self;
+ case 7:
+ return num_attr_bytes;
+ case 8:
+ return cpv__start;
+ default:
+ return 0;
+ }
}
void Glulxe::accel_error(const char *msg) {
- glk_put_char('\n');
- glk_put_string(msg);
- glk_put_char('\n');
+ glk_put_char('\n');
+ glk_put_string(msg);
+ glk_put_char('\n');
}
int Glulxe::obj_in_class(uint obj) {
- // This checks whether obj is contained in Class, not whether it is a member of Class
- return (Mem4(obj + 13 + num_attr_bytes) == class_metaclass);
+ // This checks whether obj is contained in Class, not whether it is a member of Class
+ return (Mem4(obj + 13 + num_attr_bytes) == class_metaclass);
}
uint Glulxe::get_prop(uint obj, uint id) {
- uint cla = 0;
- uint prop;
- uint call_argv[2];
-
- if (id & 0xFFFF0000) {
- cla = Mem4(classes_table+((id & 0xFFFF) * 4));
- ARG(call_argv, 2, 0) = obj;
- ARG(call_argv, 2, 1) = cla;
- if (func_5_oc__cl(2, call_argv) == 0)
- return 0;
-
- id >>= 16;
- obj = cla;
- }
-
- ARG(call_argv, 2, 0) = obj;
- ARG(call_argv, 2, 1) = id;
- prop = func_2_cp__tab(2, call_argv);
- if (prop == 0)
- return 0;
-
- if (obj_in_class(obj) && (cla == 0)) {
- if ((id < indiv_prop_start) || (id >= indiv_prop_start+8))
- return 0;
- }
-
- if (Mem4(self) != obj) {
- if (Mem1(prop + 9) & 1)
- return 0;
- }
- return prop;
+ uint cla = 0;
+ uint prop;
+ uint call_argv[2];
+
+ if (id & 0xFFFF0000) {
+ cla = Mem4(classes_table + ((id & 0xFFFF) * 4));
+ ARG(call_argv, 2, 0) = obj;
+ ARG(call_argv, 2, 1) = cla;
+ if (func_5_oc__cl(2, call_argv) == 0)
+ return 0;
+
+ id >>= 16;
+ obj = cla;
+ }
+
+ ARG(call_argv, 2, 0) = obj;
+ ARG(call_argv, 2, 1) = id;
+ prop = func_2_cp__tab(2, call_argv);
+ if (prop == 0)
+ return 0;
+
+ if (obj_in_class(obj) && (cla == 0)) {
+ if ((id < indiv_prop_start) || (id >= indiv_prop_start + 8))
+ return 0;
+ }
+
+ if (Mem4(self) != obj) {
+ if (Mem1(prop + 9) & 1)
+ return 0;
+ }
+ return prop;
}
uint Glulxe::get_prop_new(uint obj, uint id) {
- uint cla = 0;
- uint prop;
- uint call_argv[2];
-
- if (id & 0xFFFF0000) {
- cla = Mem4(classes_table+((id & 0xFFFF) * 4));
- ARG(call_argv, 2, 0) = obj;
- ARG(call_argv, 2, 1) = cla;
- if (func_11_oc__cl(2, call_argv) == 0)
- return 0;
-
- id >>= 16;
- obj = cla;
- }
-
- ARG(call_argv, 2, 0) = obj;
- ARG(call_argv, 2, 1) = id;
- prop = func_8_cp__tab(2, call_argv);
- if (prop == 0)
- return 0;
-
- if (obj_in_class(obj) && (cla == 0)) {
- if ((id < indiv_prop_start) || (id >= indiv_prop_start+8))
- return 0;
- }
-
- if (Mem4(self) != obj) {
- if (Mem1(prop + 9) & 1)
- return 0;
- }
- return prop;
+ uint cla = 0;
+ uint prop;
+ uint call_argv[2];
+
+ if (id & 0xFFFF0000) {
+ cla = Mem4(classes_table + ((id & 0xFFFF) * 4));
+ ARG(call_argv, 2, 0) = obj;
+ ARG(call_argv, 2, 1) = cla;
+ if (func_11_oc__cl(2, call_argv) == 0)
+ return 0;
+
+ id >>= 16;
+ obj = cla;
+ }
+
+ ARG(call_argv, 2, 0) = obj;
+ ARG(call_argv, 2, 1) = id;
+ prop = func_8_cp__tab(2, call_argv);
+ if (prop == 0)
+ return 0;
+
+ if (obj_in_class(obj) && (cla == 0)) {
+ if ((id < indiv_prop_start) || (id >= indiv_prop_start + 8))
+ return 0;
+ }
+
+ if (Mem4(self) != obj) {
+ if (Mem1(prop + 9) & 1)
+ return 0;
+ }
+ return prop;
}
uint Glulxe::func_1_z__region(uint argc, uint *argv) {
- uint addr;
- uint tb;
-
- if (argc < 1)
- return 0;
-
- addr = ARG(argv, argc, 0);
- if (addr < 36)
- return 0;
- if (addr >= endmem)
- return 0;
-
- tb = Mem1(addr);
- if (tb >= 0xE0) {
- return 3;
- }
- if (tb >= 0xC0) {
- return 2;
- }
- if (tb >= 0x70 && tb <= 0x7F && addr >= ramstart) {
- return 1;
- }
- return 0;
+ uint addr;
+ uint tb;
+
+ if (argc < 1)
+ return 0;
+
+ addr = ARG(argv, argc, 0);
+ if (addr < 36)
+ return 0;
+ if (addr >= endmem)
+ return 0;
+
+ tb = Mem1(addr);
+ if (tb >= 0xE0) {
+ return 3;
+ }
+ if (tb >= 0xC0) {
+ return 2;
+ }
+ if (tb >= 0x70 && tb <= 0x7F && addr >= ramstart) {
+ return 1;
+ }
+ return 0;
}
uint Glulxe::func_2_cp__tab(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint otab, max;
-
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
-
- if (func_1_z__region(1, &obj) != 1) {
- accel_error("[** Programming error: tried to find the \".\" of (something) **]");
- return 0;
- }
-
- otab = Mem4(obj + 16);
- if (!otab)
- return 0;
-
- max = Mem4(otab);
- otab += 4;
- /* @binarysearch id 2 otab 10 max 0 0 res; */
- return binary_search(id, 2, otab, 10, max, 0, 0);
+ uint obj;
+ uint id;
+ uint otab, max;
+
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
+
+ if (func_1_z__region(1, &obj) != 1) {
+ accel_error("[** Programming error: tried to find the \".\" of (something) **]");
+ return 0;
+ }
+
+ otab = Mem4(obj + 16);
+ if (!otab)
+ return 0;
+
+ max = Mem4(otab);
+ otab += 4;
+ /* @binarysearch id 2 otab 10 max 0 0 res; */
+ return binary_search(id, 2, otab, 10, max, 0, 0);
}
uint Glulxe::func_3_ra__pr(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint prop;
+ uint obj;
+ uint id;
+ uint prop;
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
- prop = get_prop(obj, id);
- if (prop == 0)
- return 0;
+ prop = get_prop(obj, id);
+ if (prop == 0)
+ return 0;
- return Mem4(prop + 4);
+ return Mem4(prop + 4);
}
uint Glulxe::func_4_rl__pr(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint prop;
+ uint obj;
+ uint id;
+ uint prop;
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
- prop = get_prop(obj, id);
- if (prop == 0)
- return 0;
+ prop = get_prop(obj, id);
+ if (prop == 0)
+ return 0;
- return 4 * Mem2(prop + 2);
+ return 4 * Mem2(prop + 2);
}
uint Glulxe::func_5_oc__cl(uint argc, uint *argv) {
- uint obj;
- uint cla;
- uint zr, prop, inlist, inlistlen, jx;
-
- obj = ARG_IF_GIVEN(argv, argc, 0);
- cla = ARG_IF_GIVEN(argv, argc, 1);
-
- zr = func_1_z__region(1, &obj);
- if (zr == 3)
- return (cla == string_metaclass) ? 1 : 0;
- if (zr == 2)
- return (cla == routine_metaclass) ? 1 : 0;
- if (zr != 1)
- return 0;
-
- if (cla == class_metaclass) {
- if (obj_in_class(obj))
- return 1;
- if (obj == class_metaclass)
- return 1;
- if (obj == string_metaclass)
- return 1;
- if (obj == routine_metaclass)
- return 1;
- if (obj == object_metaclass)
- return 1;
- return 0;
- }
- if (cla == object_metaclass) {
- if (obj_in_class(obj))
- return 0;
- if (obj == class_metaclass)
- return 0;
- if (obj == string_metaclass)
- return 0;
- if (obj == routine_metaclass)
- return 0;
- if (obj == object_metaclass)
- return 0;
- return 1;
- }
- if ((cla == string_metaclass) || (cla == routine_metaclass))
- return 0;
-
- if (!obj_in_class(cla)) {
- accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]");
- return 0;
- }
-
- prop = get_prop(obj, 2);
- if (prop == 0)
- return 0;
-
- inlist = Mem4(prop + 4);
- if (inlist == 0)
- return 0;
-
- inlistlen = Mem2(prop + 2);
- for (jx = 0; jx < inlistlen; jx++) {
- if (Mem4(inlist + (4 * jx)) == cla)
- return 1;
- }
- return 0;
+ uint obj;
+ uint cla;
+ uint zr, prop, inlist, inlistlen, jx;
+
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ cla = ARG_IF_GIVEN(argv, argc, 1);
+
+ zr = func_1_z__region(1, &obj);
+ if (zr == 3)
+ return (cla == string_metaclass) ? 1 : 0;
+ if (zr == 2)
+ return (cla == routine_metaclass) ? 1 : 0;
+ if (zr != 1)
+ return 0;
+
+ if (cla == class_metaclass) {
+ if (obj_in_class(obj))
+ return 1;
+ if (obj == class_metaclass)
+ return 1;
+ if (obj == string_metaclass)
+ return 1;
+ if (obj == routine_metaclass)
+ return 1;
+ if (obj == object_metaclass)
+ return 1;
+ return 0;
+ }
+ if (cla == object_metaclass) {
+ if (obj_in_class(obj))
+ return 0;
+ if (obj == class_metaclass)
+ return 0;
+ if (obj == string_metaclass)
+ return 0;
+ if (obj == routine_metaclass)
+ return 0;
+ if (obj == object_metaclass)
+ return 0;
+ return 1;
+ }
+ if ((cla == string_metaclass) || (cla == routine_metaclass))
+ return 0;
+
+ if (!obj_in_class(cla)) {
+ accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]");
+ return 0;
+ }
+
+ prop = get_prop(obj, 2);
+ if (prop == 0)
+ return 0;
+
+ inlist = Mem4(prop + 4);
+ if (inlist == 0)
+ return 0;
+
+ inlistlen = Mem2(prop + 2);
+ for (jx = 0; jx < inlistlen; jx++) {
+ if (Mem4(inlist + (4 * jx)) == cla)
+ return 1;
+ }
+ return 0;
}
uint Glulxe::func_6_rv__pr(uint argc, uint *argv) {
- uint id;
- uint addr;
+ uint id;
+ uint addr;
- id = ARG_IF_GIVEN(argv, argc, 1);
+ id = ARG_IF_GIVEN(argv, argc, 1);
- addr = func_3_ra__pr(argc, argv);
+ addr = func_3_ra__pr(argc, argv);
- if (addr == 0) {
- if ((id > 0) && (id < indiv_prop_start))
- return Mem4(cpv__start + (4 * id));
+ if (addr == 0) {
+ if ((id > 0) && (id < indiv_prop_start))
+ return Mem4(cpv__start + (4 * id));
- accel_error("[** Programming error: tried to read (something) **]");
- return 0;
- }
+ accel_error("[** Programming error: tried to read (something) **]");
+ return 0;
+ }
- return Mem4(addr);
+ return Mem4(addr);
}
uint Glulxe::func_7_op__pr(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint zr;
-
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
-
- zr = func_1_z__region(1, &obj);
- if (zr == 3) {
- /* print is INDIV_PROP_START+6 */
- if (id == indiv_prop_start+6)
- return 1;
- /* print_to_array is INDIV_PROP_START+7 */
- if (id == indiv_prop_start+7)
- return 1;
- return 0;
- }
- if (zr == 2) {
- /* call is INDIV_PROP_START+5 */
- return ((id == indiv_prop_start+5) ? 1 : 0);
- }
- if (zr != 1)
- return 0;
-
- if ((id >= indiv_prop_start) && (id < indiv_prop_start+8)) {
- if (obj_in_class(obj))
- return 1;
- }
-
- return ((func_3_ra__pr(argc, argv)) ? 1 : 0);
+ uint obj;
+ uint id;
+ uint zr;
+
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
+
+ zr = func_1_z__region(1, &obj);
+ if (zr == 3) {
+ /* print is INDIV_PROP_START+6 */
+ if (id == indiv_prop_start + 6)
+ return 1;
+ /* print_to_array is INDIV_PROP_START+7 */
+ if (id == indiv_prop_start + 7)
+ return 1;
+ return 0;
+ }
+ if (zr == 2) {
+ /* call is INDIV_PROP_START+5 */
+ return ((id == indiv_prop_start + 5) ? 1 : 0);
+ }
+ if (zr != 1)
+ return 0;
+
+ if ((id >= indiv_prop_start) && (id < indiv_prop_start + 8)) {
+ if (obj_in_class(obj))
+ return 1;
+ }
+
+ return ((func_3_ra__pr(argc, argv)) ? 1 : 0);
}
uint Glulxe::func_8_cp__tab(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint otab, max;
-
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
-
- if (func_1_z__region(1, &obj) != 1) {
- accel_error("[** Programming error: tried to find the \".\" of (something) **]");
- return 0;
- }
-
- otab = Mem4(obj + 4*(3+(int)(num_attr_bytes/4)));
- if (!otab)
- return 0;
-
- max = Mem4(otab);
- otab += 4;
- /* @binarysearch id 2 otab 10 max 0 0 res; */
- return binary_search(id, 2, otab, 10, max, 0, 0);
+ uint obj;
+ uint id;
+ uint otab, max;
+
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
+
+ if (func_1_z__region(1, &obj) != 1) {
+ accel_error("[** Programming error: tried to find the \".\" of (something) **]");
+ return 0;
+ }
+
+ otab = Mem4(obj + 4 * (3 + (int)(num_attr_bytes / 4)));
+ if (!otab)
+ return 0;
+
+ max = Mem4(otab);
+ otab += 4;
+ /* @binarysearch id 2 otab 10 max 0 0 res; */
+ return binary_search(id, 2, otab, 10, max, 0, 0);
}
uint Glulxe::func_9_ra__pr(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint prop;
+ uint obj;
+ uint id;
+ uint prop;
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
- prop = get_prop_new(obj, id);
- if (prop == 0)
- return 0;
+ prop = get_prop_new(obj, id);
+ if (prop == 0)
+ return 0;
- return Mem4(prop + 4);
+ return Mem4(prop + 4);
}
uint Glulxe::func_10_rl__pr(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint prop;
+ uint obj;
+ uint id;
+ uint prop;
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
- prop = get_prop_new(obj, id);
- if (prop == 0)
- return 0;
+ prop = get_prop_new(obj, id);
+ if (prop == 0)
+ return 0;
- return 4 * Mem2(prop + 2);
+ return 4 * Mem2(prop + 2);
}
uint Glulxe::func_11_oc__cl(uint argc, uint *argv) {
- uint obj;
- uint cla;
- uint zr, prop, inlist, inlistlen, jx;
-
- obj = ARG_IF_GIVEN(argv, argc, 0);
- cla = ARG_IF_GIVEN(argv, argc, 1);
-
- zr = func_1_z__region(1, &obj);
- if (zr == 3)
- return (cla == string_metaclass) ? 1 : 0;
- if (zr == 2)
- return (cla == routine_metaclass) ? 1 : 0;
- if (zr != 1)
- return 0;
-
- if (cla == class_metaclass) {
- if (obj_in_class(obj))
- return 1;
- if (obj == class_metaclass)
- return 1;
- if (obj == string_metaclass)
- return 1;
- if (obj == routine_metaclass)
- return 1;
- if (obj == object_metaclass)
- return 1;
- return 0;
- }
- if (cla == object_metaclass) {
- if (obj_in_class(obj))
- return 0;
- if (obj == class_metaclass)
- return 0;
- if (obj == string_metaclass)
- return 0;
- if (obj == routine_metaclass)
- return 0;
- if (obj == object_metaclass)
- return 0;
- return 1;
- }
- if ((cla == string_metaclass) || (cla == routine_metaclass))
- return 0;
-
- if (!obj_in_class(cla)) {
- accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]");
- return 0;
- }
-
- prop = get_prop_new(obj, 2);
- if (prop == 0)
- return 0;
-
- inlist = Mem4(prop + 4);
- if (inlist == 0)
- return 0;
-
- inlistlen = Mem2(prop + 2);
- for (jx = 0; jx < inlistlen; jx++) {
- if (Mem4(inlist + (4 * jx)) == cla)
- return 1;
- }
- return 0;
+ uint obj;
+ uint cla;
+ uint zr, prop, inlist, inlistlen, jx;
+
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ cla = ARG_IF_GIVEN(argv, argc, 1);
+
+ zr = func_1_z__region(1, &obj);
+ if (zr == 3)
+ return (cla == string_metaclass) ? 1 : 0;
+ if (zr == 2)
+ return (cla == routine_metaclass) ? 1 : 0;
+ if (zr != 1)
+ return 0;
+
+ if (cla == class_metaclass) {
+ if (obj_in_class(obj))
+ return 1;
+ if (obj == class_metaclass)
+ return 1;
+ if (obj == string_metaclass)
+ return 1;
+ if (obj == routine_metaclass)
+ return 1;
+ if (obj == object_metaclass)
+ return 1;
+ return 0;
+ }
+ if (cla == object_metaclass) {
+ if (obj_in_class(obj))
+ return 0;
+ if (obj == class_metaclass)
+ return 0;
+ if (obj == string_metaclass)
+ return 0;
+ if (obj == routine_metaclass)
+ return 0;
+ if (obj == object_metaclass)
+ return 0;
+ return 1;
+ }
+ if ((cla == string_metaclass) || (cla == routine_metaclass))
+ return 0;
+
+ if (!obj_in_class(cla)) {
+ accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]");
+ return 0;
+ }
+
+ prop = get_prop_new(obj, 2);
+ if (prop == 0)
+ return 0;
+
+ inlist = Mem4(prop + 4);
+ if (inlist == 0)
+ return 0;
+
+ inlistlen = Mem2(prop + 2);
+ for (jx = 0; jx < inlistlen; jx++) {
+ if (Mem4(inlist + (4 * jx)) == cla)
+ return 1;
+ }
+ return 0;
}
uint Glulxe::func_12_rv__pr(uint argc, uint *argv) {
- uint id;
- uint addr;
+ uint id;
+ uint addr;
- id = ARG_IF_GIVEN(argv, argc, 1);
+ id = ARG_IF_GIVEN(argv, argc, 1);
- addr = func_9_ra__pr(argc, argv);
+ addr = func_9_ra__pr(argc, argv);
- if (addr == 0) {
- if ((id > 0) && (id < indiv_prop_start))
- return Mem4(cpv__start + (4 * id));
+ if (addr == 0) {
+ if ((id > 0) && (id < indiv_prop_start))
+ return Mem4(cpv__start + (4 * id));
- accel_error("[** Programming error: tried to read (something) **]");
- return 0;
- }
+ accel_error("[** Programming error: tried to read (something) **]");
+ return 0;
+ }
- return Mem4(addr);
+ return Mem4(addr);
}
uint Glulxe::func_13_op__pr(uint argc, uint *argv) {
- uint obj;
- uint id;
- uint zr;
-
- obj = ARG_IF_GIVEN(argv, argc, 0);
- id = ARG_IF_GIVEN(argv, argc, 1);
-
- zr = func_1_z__region(1, &obj);
- if (zr == 3) {
- /* print is INDIV_PROP_START+6 */
- if (id == indiv_prop_start+6)
- return 1;
- /* print_to_array is INDIV_PROP_START+7 */
- if (id == indiv_prop_start+7)
- return 1;
- return 0;
- }
- if (zr == 2) {
- /* call is INDIV_PROP_START+5 */
- return ((id == indiv_prop_start+5) ? 1 : 0);
- }
- if (zr != 1)
- return 0;
-
- if ((id >= indiv_prop_start) && (id < indiv_prop_start+8)) {
- if (obj_in_class(obj))
- return 1;
- }
-
- return ((func_9_ra__pr(argc, argv)) ? 1 : 0);
+ uint obj;
+ uint id;
+ uint zr;
+
+ obj = ARG_IF_GIVEN(argv, argc, 0);
+ id = ARG_IF_GIVEN(argv, argc, 1);
+
+ zr = func_1_z__region(1, &obj);
+ if (zr == 3) {
+ /* print is INDIV_PROP_START+6 */
+ if (id == indiv_prop_start + 6)
+ return 1;
+ /* print_to_array is INDIV_PROP_START+7 */
+ if (id == indiv_prop_start + 7)
+ return 1;
+ return 0;
+ }
+ if (zr == 2) {
+ /* call is INDIV_PROP_START+5 */
+ return ((id == indiv_prop_start + 5) ? 1 : 0);
+ }
+ if (zr != 1)
+ return 0;
+
+ if ((id >= indiv_prop_start) && (id < indiv_prop_start + 8)) {
+ if (obj_in_class(obj))
+ return 1;
+ }
+
+ return ((func_9_ra__pr(argc, argv)) ? 1 : 0);
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/exec.cpp b/engines/glk/glulxe/exec.cpp
index f314ca43e2..55cd918ebb 100644
--- a/engines/glk/glulxe/exec.cpp
+++ b/engines/glk/glulxe/exec.cpp
@@ -26,1042 +26,1023 @@ namespace Glk {
namespace Glulxe {
void Glulxe::execute_loop() {
- bool done_executing = false;
- int ix;
- uint opcode;
- const operandlist_t *oplist;
- oparg_t inst[MAX_OPERANDS];
- uint value, addr, val0, val1;
- int vals0, vals1;
- uint *arglist;
- uint arglistfix[3];
+ bool done_executing = false;
+ int ix;
+ uint opcode;
+ const operandlist_t *oplist;
+ oparg_t inst[MAX_OPERANDS];
+ uint value, addr, val0, val1;
+ int vals0, vals1;
+ uint *arglist;
+ uint arglistfix[3];
#ifdef FLOAT_SUPPORT
- gfloat32 valf, valf1, valf2;
+ gfloat32 valf, valf1, valf2;
#endif /* FLOAT_SUPPORT */
- while (!done_executing) {
-
- profile_tick();
- debugger_tick();
- /* Do OS-specific processing, if appropriate. */
- glk_tick();
-
- /* Stash the current opcode's address, in case the interpreter needs to serialize the VM state out-of-band. */
- prevpc = pc;
-
- /* Fetch the opcode number. */
- opcode = Mem1(pc);
- pc++;
- if (opcode & 0x80) {
- /* More than one-byte opcode. */
- if (opcode & 0x40) {
- /* Four-byte opcode */
- opcode &= 0x3F;
- opcode = (opcode << 8) | Mem1(pc);
- pc++;
- opcode = (opcode << 8) | Mem1(pc);
- pc++;
- opcode = (opcode << 8) | Mem1(pc);
- pc++;
- }
- else {
- /* Two-byte opcode */
- opcode &= 0x7F;
- opcode = (opcode << 8) | Mem1(pc);
- pc++;
- }
- }
-
- /* Now we have an opcode number. */
-
- /* Fetch the structure that describes how the operands for this
- opcode are arranged. This is a pointer to an immutable,
- static object. */
- if (opcode < 0x80)
- oplist = fast_operandlist[opcode];
- else
- oplist = lookup_operandlist(opcode);
-
- if (!oplist)
- fatal_error_i("Encountered unknown opcode.", opcode);
-
- /* Based on the oplist structure, load the actual operand values
- into inst. This moves the PC up to the end of the instruction. */
- parse_operands(inst, oplist);
-
- /* Perform the opcode. This switch statement is split in two, based
- on some paranoid suspicions about the ability of compilers to
- optimize large-range switches. Ignore that. */
-
- if (opcode < 0x80) {
-
- switch (opcode) {
-
- case op_nop:
- break;
-
- case op_add:
- value = inst[0].value + inst[1].value;
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_sub:
- value = inst[0].value - inst[1].value;
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_mul:
- value = inst[0].value * inst[1].value;
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_div:
- vals0 = inst[0].value;
- vals1 = inst[1].value;
- if (vals1 == 0)
- fatal_error("Division by zero.");
- /* Since C doesn't guarantee the results of division of negative
- numbers, we carefully convert everything to positive values
- first. They have to be unsigned values, too, otherwise the
- 0x80000000 case goes wonky. */
- if (vals0 < 0) {
- val0 = (-vals0);
- if (vals1 < 0) {
- val1 = (-vals1);
- value = val0 / val1;
- }
- else {
- val1 = vals1;
- value = -(int)(val0 / val1);
- }
- }
- else {
- val0 = vals0;
- if (vals1 < 0) {
- val1 = (-vals1);
- value = -(int)(val0 / val1);
- }
- else {
- val1 = vals1;
- value = val0 / val1;
- }
- }
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_mod:
- vals0 = inst[0].value;
- vals1 = inst[1].value;
- if (vals1 == 0)
- fatal_error("Division by zero doing remainder.");
- if (vals1 < 0) {
- val1 = -vals1;
- }
- else {
- val1 = vals1;
- }
- if (vals0 < 0) {
- val0 = (-vals0);
- value = -(int)(val0 % val1);
- }
- else {
- val0 = vals0;
- value = val0 % val1;
- }
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_neg:
- vals0 = inst[0].value;
- value = (-vals0);
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
-
- case op_bitand:
- value = (inst[0].value & inst[1].value);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_bitor:
- value = (inst[0].value | inst[1].value);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_bitxor:
- value = (inst[0].value ^ inst[1].value);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_bitnot:
- value = ~(inst[0].value);
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
-
- case op_shiftl:
- vals0 = inst[1].value;
- if (vals0 < 0 || vals0 >= 32)
- value = 0;
- else
- value = ((uint)(inst[0].value) << (uint)vals0);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_ushiftr:
- vals0 = inst[1].value;
- if (vals0 < 0 || vals0 >= 32)
- value = 0;
- else
- value = ((uint)(inst[0].value) >> (uint)vals0);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_sshiftr:
- vals0 = inst[1].value;
- if (vals0 < 0 || vals0 >= 32) {
- if (inst[0].value & 0x80000000)
- value = 0xFFFFFFFF;
- else
- value = 0;
- }
- else {
- /* This is somewhat foolhardy -- C doesn't guarantee that
- right-shifting a signed value replicates the sign bit.
- We'll assume it for now. */
- value = ((int)(inst[0].value) >> (int)vals0);
- }
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
-
- case op_jump:
- value = inst[0].value;
- /* fall through to PerformJump label. */
-
- PerformJump: /* goto label for successful jumping... ironic, no? */
- if (value == 0 || value == 1) {
- /* Return from function. This is exactly what happens in
- return_op, but it's only a few lines of code, so I won't
- bother with a "goto". */
- leave_function();
- if (stackptr == 0) {
- done_executing = true;
- break;
- }
- pop_callstub(value); /* zero or one */
- }
- else {
- /* Branch to a new PC value. */
- pc = (pc + value - 2);
- }
- break;
-
- case op_jz:
- if (inst[0].value == 0) {
- value = inst[1].value;
- goto PerformJump;
- }
- break;
- case op_jnz:
- if (inst[0].value != 0) {
- value = inst[1].value;
- goto PerformJump;
- }
- break;
- case op_jeq:
- if (inst[0].value == inst[1].value) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jne:
- if (inst[0].value != inst[1].value) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jlt:
- vals0 = inst[0].value;
- vals1 = inst[1].value;
- if (vals0 < vals1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jgt:
- vals0 = inst[0].value;
- vals1 = inst[1].value;
- if (vals0 > vals1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jle:
- vals0 = inst[0].value;
- vals1 = inst[1].value;
- if (vals0 <= vals1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jge:
- vals0 = inst[0].value;
- vals1 = inst[1].value;
- if (vals0 >= vals1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jltu:
- val0 = inst[0].value;
- val1 = inst[1].value;
- if (val0 < val1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jgtu:
- val0 = inst[0].value;
- val1 = inst[1].value;
- if (val0 > val1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jleu:
- val0 = inst[0].value;
- val1 = inst[1].value;
- if (val0 <= val1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jgeu:
- val0 = inst[0].value;
- val1 = inst[1].value;
- if (val0 >= val1) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
-
- case op_call:
- value = inst[1].value;
- arglist = pop_arguments(value, 0);
- push_callstub(inst[2].desttype, inst[2].value);
- enter_function(inst[0].value, value, arglist);
- break;
- case op_return:
- leave_function();
- if (stackptr == 0) {
- done_executing = true;
- break;
- }
- pop_callstub(inst[0].value);
- break;
- case op_tailcall:
- value = inst[1].value;
- arglist = pop_arguments(value, 0);
- leave_function();
- enter_function(inst[0].value, value, arglist);
- break;
-
- case op_catch:
- push_callstub(inst[0].desttype, inst[0].value);
- value = inst[1].value;
- val0 = stackptr;
- store_operand(inst[0].desttype, inst[0].value, val0);
- goto PerformJump;
- break;
- case op_throw:
- profile_fail("throw");
- value = inst[0].value;
- stackptr = inst[1].value;
- pop_callstub(value);
- break;
-
- case op_copy:
- value = inst[0].value;
+ while (!done_executing) {
+
+ profile_tick();
+ debugger_tick();
+ /* Do OS-specific processing, if appropriate. */
+ glk_tick();
+
+ /* Stash the current opcode's address, in case the interpreter needs to serialize the VM state out-of-band. */
+ prevpc = pc;
+
+ /* Fetch the opcode number. */
+ opcode = Mem1(pc);
+ pc++;
+ if (opcode & 0x80) {
+ /* More than one-byte opcode. */
+ if (opcode & 0x40) {
+ /* Four-byte opcode */
+ opcode &= 0x3F;
+ opcode = (opcode << 8) | Mem1(pc);
+ pc++;
+ opcode = (opcode << 8) | Mem1(pc);
+ pc++;
+ opcode = (opcode << 8) | Mem1(pc);
+ pc++;
+ } else {
+ /* Two-byte opcode */
+ opcode &= 0x7F;
+ opcode = (opcode << 8) | Mem1(pc);
+ pc++;
+ }
+ }
+
+ /* Now we have an opcode number. */
+
+ /* Fetch the structure that describes how the operands for this
+ opcode are arranged. This is a pointer to an immutable,
+ static object. */
+ if (opcode < 0x80)
+ oplist = fast_operandlist[opcode];
+ else
+ oplist = lookup_operandlist(opcode);
+
+ if (!oplist)
+ fatal_error_i("Encountered unknown opcode.", opcode);
+
+ /* Based on the oplist structure, load the actual operand values
+ into inst. This moves the PC up to the end of the instruction. */
+ parse_operands(inst, oplist);
+
+ /* Perform the opcode. This switch statement is split in two, based
+ on some paranoid suspicions about the ability of compilers to
+ optimize large-range switches. Ignore that. */
+
+ if (opcode < 0x80) {
+
+ switch (opcode) {
+
+ case op_nop:
+ break;
+
+ case op_add:
+ value = inst[0].value + inst[1].value;
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_sub:
+ value = inst[0].value - inst[1].value;
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_mul:
+ value = inst[0].value * inst[1].value;
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_div:
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
+ if (vals1 == 0)
+ fatal_error("Division by zero.");
+ /* Since C doesn't guarantee the results of division of negative
+ numbers, we carefully convert everything to positive values
+ first. They have to be unsigned values, too, otherwise the
+ 0x80000000 case goes wonky. */
+ if (vals0 < 0) {
+ val0 = (-vals0);
+ if (vals1 < 0) {
+ val1 = (-vals1);
+ value = val0 / val1;
+ } else {
+ val1 = vals1;
+ value = -(int)(val0 / val1);
+ }
+ } else {
+ val0 = vals0;
+ if (vals1 < 0) {
+ val1 = (-vals1);
+ value = -(int)(val0 / val1);
+ } else {
+ val1 = vals1;
+ value = val0 / val1;
+ }
+ }
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_mod:
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
+ if (vals1 == 0)
+ fatal_error("Division by zero doing remainder.");
+ if (vals1 < 0) {
+ val1 = -vals1;
+ } else {
+ val1 = vals1;
+ }
+ if (vals0 < 0) {
+ val0 = (-vals0);
+ value = -(int)(val0 % val1);
+ } else {
+ val0 = vals0;
+ value = val0 % val1;
+ }
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_neg:
+ vals0 = inst[0].value;
+ value = (-vals0);
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+
+ case op_bitand:
+ value = (inst[0].value & inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_bitor:
+ value = (inst[0].value | inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_bitxor:
+ value = (inst[0].value ^ inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_bitnot:
+ value = ~(inst[0].value);
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+
+ case op_shiftl:
+ vals0 = inst[1].value;
+ if (vals0 < 0 || vals0 >= 32)
+ value = 0;
+ else
+ value = ((uint)(inst[0].value) << (uint)vals0);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_ushiftr:
+ vals0 = inst[1].value;
+ if (vals0 < 0 || vals0 >= 32)
+ value = 0;
+ else
+ value = ((uint)(inst[0].value) >> (uint)vals0);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_sshiftr:
+ vals0 = inst[1].value;
+ if (vals0 < 0 || vals0 >= 32) {
+ if (inst[0].value & 0x80000000)
+ value = 0xFFFFFFFF;
+ else
+ value = 0;
+ } else {
+ /* This is somewhat foolhardy -- C doesn't guarantee that
+ right-shifting a signed value replicates the sign bit.
+ We'll assume it for now. */
+ value = ((int)(inst[0].value) >> (int)vals0);
+ }
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+
+ case op_jump:
+ value = inst[0].value;
+ /* fall through to PerformJump label. */
+
+PerformJump: /* goto label for successful jumping... ironic, no? */
+ if (value == 0 || value == 1) {
+ /* Return from function. This is exactly what happens in
+ return_op, but it's only a few lines of code, so I won't
+ bother with a "goto". */
+ leave_function();
+ if (stackptr == 0) {
+ done_executing = true;
+ break;
+ }
+ pop_callstub(value); /* zero or one */
+ } else {
+ /* Branch to a new PC value. */
+ pc = (pc + value - 2);
+ }
+ break;
+
+ case op_jz:
+ if (inst[0].value == 0) {
+ value = inst[1].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jnz:
+ if (inst[0].value != 0) {
+ value = inst[1].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jeq:
+ if (inst[0].value == inst[1].value) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jne:
+ if (inst[0].value != inst[1].value) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jlt:
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
+ if (vals0 < vals1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jgt:
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
+ if (vals0 > vals1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jle:
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
+ if (vals0 <= vals1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jge:
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
+ if (vals0 >= vals1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jltu:
+ val0 = inst[0].value;
+ val1 = inst[1].value;
+ if (val0 < val1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jgtu:
+ val0 = inst[0].value;
+ val1 = inst[1].value;
+ if (val0 > val1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jleu:
+ val0 = inst[0].value;
+ val1 = inst[1].value;
+ if (val0 <= val1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jgeu:
+ val0 = inst[0].value;
+ val1 = inst[1].value;
+ if (val0 >= val1) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+
+ case op_call:
+ value = inst[1].value;
+ arglist = pop_arguments(value, 0);
+ push_callstub(inst[2].desttype, inst[2].value);
+ enter_function(inst[0].value, value, arglist);
+ break;
+ case op_return:
+ leave_function();
+ if (stackptr == 0) {
+ done_executing = true;
+ break;
+ }
+ pop_callstub(inst[0].value);
+ break;
+ case op_tailcall:
+ value = inst[1].value;
+ arglist = pop_arguments(value, 0);
+ leave_function();
+ enter_function(inst[0].value, value, arglist);
+ break;
+
+ case op_catch:
+ push_callstub(inst[0].desttype, inst[0].value);
+ value = inst[1].value;
+ val0 = stackptr;
+ store_operand(inst[0].desttype, inst[0].value, val0);
+ goto PerformJump;
+ break;
+ case op_throw:
+ profile_fail("throw");
+ value = inst[0].value;
+ stackptr = inst[1].value;
+ pop_callstub(value);
+ break;
+
+ case op_copy:
+ value = inst[0].value;
#ifdef TOLERATE_SUPERGLUS_BUG
- if (inst[1].desttype == 1 && inst[1].value == 0)
- inst[1].desttype = 0;
+ if (inst[1].desttype == 1 && inst[1].value == 0)
+ inst[1].desttype = 0;
#endif /* TOLERATE_SUPERGLUS_BUG */
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_copys:
- value = inst[0].value;
- store_operand_s(inst[1].desttype, inst[1].value, value);
- break;
- case op_copyb:
- value = inst[0].value;
- store_operand_b(inst[1].desttype, inst[1].value, value);
- break;
-
- case op_sexs:
- val0 = inst[0].value;
- if (val0 & 0x8000)
- val0 |= 0xFFFF0000;
- else
- val0 &= 0x0000FFFF;
- store_operand(inst[1].desttype, inst[1].value, val0);
- break;
- case op_sexb:
- val0 = inst[0].value;
- if (val0 & 0x80)
- val0 |= 0xFFFFFF00;
- else
- val0 &= 0x000000FF;
- store_operand(inst[1].desttype, inst[1].value, val0);
- break;
-
- case op_aload:
- value = inst[0].value;
- value += 4 * inst[1].value;
- val0 = Mem4(value);
- store_operand(inst[2].desttype, inst[2].value, val0);
- break;
- case op_aloads:
- value = inst[0].value;
- value += 2 * inst[1].value;
- val0 = Mem2(value);
- store_operand(inst[2].desttype, inst[2].value, val0);
- break;
- case op_aloadb:
- value = inst[0].value;
- value += inst[1].value;
- val0 = Mem1(value);
- store_operand(inst[2].desttype, inst[2].value, val0);
- break;
- case op_aloadbit:
- value = inst[0].value;
- vals0 = inst[1].value;
- val1 = (vals0 & 7);
- if (vals0 >= 0)
- value += (vals0 >> 3);
- else
- value -= (1 + ((-1 - vals0) >> 3));
- if (Mem1(value) & (1 << val1))
- val0 = 1;
- else
- val0 = 0;
- store_operand(inst[2].desttype, inst[2].value, val0);
- break;
-
- case op_astore:
- value = inst[0].value;
- value += 4 * inst[1].value;
- val0 = inst[2].value;
- MemW4(value, val0);
- break;
- case op_astores:
- value = inst[0].value;
- value += 2 * inst[1].value;
- val0 = inst[2].value;
- MemW2(value, val0);
- break;
- case op_astoreb:
- value = inst[0].value;
- value += inst[1].value;
- val0 = inst[2].value;
- MemW1(value, val0);
- break;
- case op_astorebit:
- value = inst[0].value;
- vals0 = inst[1].value;
- val1 = (vals0 & 7);
- if (vals0 >= 0)
- value += (vals0 >> 3);
- else
- value -= (1 + ((-1 - vals0) >> 3));
- val0 = Mem1(value);
- if (inst[2].value)
- val0 |= (1 << val1);
- else
- val0 &= ~((uint)(1 << val1));
- MemW1(value, val0);
- break;
-
- case op_stkcount:
- value = (stackptr - valstackbase) / 4;
- store_operand(inst[0].desttype, inst[0].value, value);
- break;
- case op_stkpeek:
- vals0 = inst[0].value * 4;
- if (vals0 < 0 || vals0 >= (int)(stackptr - valstackbase))
- fatal_error("Stkpeek outside current stack range.");
- value = Stk4(stackptr - (vals0+4));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_stkswap:
- if (stackptr < valstackbase+8) {
- fatal_error("Stack underflow in stkswap.");
- }
- val0 = Stk4(stackptr-4);
- val1 = Stk4(stackptr-8);
- StkW4(stackptr-4, val1);
- StkW4(stackptr-8, val0);
- break;
- case op_stkcopy:
- vals0 = inst[0].value;
- if (vals0 < 0)
- fatal_error("Negative operand in stkcopy.");
- if (vals0 == 0)
- break;
- if (stackptr < valstackbase+vals0*4)
- fatal_error("Stack underflow in stkcopy.");
- if (stackptr + vals0*4 > stacksize)
- fatal_error("Stack overflow in stkcopy.");
- addr = stackptr - vals0*4;
- for (ix=0; ix<vals0; ix++) {
- value = Stk4(addr + ix*4);
- StkW4(stackptr + ix*4, value);
- }
- stackptr += vals0*4;
- break;
- case op_stkroll:
- vals0 = inst[0].value;
- vals1 = inst[1].value;
- if (vals0 < 0)
- fatal_error("Negative operand in stkroll.");
- if (stackptr < valstackbase+vals0*4)
- fatal_error("Stack underflow in stkroll.");
- if (vals0 == 0)
- break;
- /* The following is a bit ugly. We want to do vals1 = vals0-vals1,
- because rolling down is sort of easier than rolling up. But
- we also want to take the result mod vals0. The % operator is
- annoying for negative numbers, so we need to do this in two
- cases. */
- if (vals1 > 0) {
- vals1 = vals1 % vals0;
- vals1 = (vals0) - vals1;
- }
- else {
- vals1 = (-vals1) % vals0;
- }
- if (vals1 == 0)
- break;
- addr = stackptr - vals0*4;
- for (ix=0; ix<vals1; ix++) {
- value = Stk4(addr + ix*4);
- StkW4(stackptr + ix*4, value);
- }
- for (ix=0; ix<vals0; ix++) {
- value = Stk4(addr + (vals1+ix)*4);
- StkW4(addr + ix*4, value);
- }
- break;
-
- case op_streamchar:
- profile_in(0xE0000001, stackptr, false);
- value = inst[0].value & 0xFF;
- (this->*stream_char_handler)(value);
- profile_out(stackptr);
- break;
- case op_streamunichar:
- profile_in(0xE0000002, stackptr, false);
- value = inst[0].value;
- (this->*stream_unichar_handler)(value);
- profile_out(stackptr);
- break;
- case op_streamnum:
- profile_in(0xE0000003, stackptr, false);
- vals0 = inst[0].value;
- stream_num(vals0, false, 0);
- profile_out(stackptr);
- break;
- case op_streamstr:
- profile_in(0xE0000004, stackptr, false);
- stream_string(inst[0].value, 0, 0);
- profile_out(stackptr);
- break;
-
- default:
- fatal_error_i("Executed unknown opcode.", opcode);
- }
- }
- else {
-
- switch (opcode) {
-
- case op_gestalt:
- value = do_gestalt(inst[0].value, inst[1].value);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
-
- case op_debugtrap:
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_copys:
+ value = inst[0].value;
+ store_operand_s(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_copyb:
+ value = inst[0].value;
+ store_operand_b(inst[1].desttype, inst[1].value, value);
+ break;
+
+ case op_sexs:
+ val0 = inst[0].value;
+ if (val0 & 0x8000)
+ val0 |= 0xFFFF0000;
+ else
+ val0 &= 0x0000FFFF;
+ store_operand(inst[1].desttype, inst[1].value, val0);
+ break;
+ case op_sexb:
+ val0 = inst[0].value;
+ if (val0 & 0x80)
+ val0 |= 0xFFFFFF00;
+ else
+ val0 &= 0x000000FF;
+ store_operand(inst[1].desttype, inst[1].value, val0);
+ break;
+
+ case op_aload:
+ value = inst[0].value;
+ value += 4 * inst[1].value;
+ val0 = Mem4(value);
+ store_operand(inst[2].desttype, inst[2].value, val0);
+ break;
+ case op_aloads:
+ value = inst[0].value;
+ value += 2 * inst[1].value;
+ val0 = Mem2(value);
+ store_operand(inst[2].desttype, inst[2].value, val0);
+ break;
+ case op_aloadb:
+ value = inst[0].value;
+ value += inst[1].value;
+ val0 = Mem1(value);
+ store_operand(inst[2].desttype, inst[2].value, val0);
+ break;
+ case op_aloadbit:
+ value = inst[0].value;
+ vals0 = inst[1].value;
+ val1 = (vals0 & 7);
+ if (vals0 >= 0)
+ value += (vals0 >> 3);
+ else
+ value -= (1 + ((-1 - vals0) >> 3));
+ if (Mem1(value) & (1 << val1))
+ val0 = 1;
+ else
+ val0 = 0;
+ store_operand(inst[2].desttype, inst[2].value, val0);
+ break;
+
+ case op_astore:
+ value = inst[0].value;
+ value += 4 * inst[1].value;
+ val0 = inst[2].value;
+ MemW4(value, val0);
+ break;
+ case op_astores:
+ value = inst[0].value;
+ value += 2 * inst[1].value;
+ val0 = inst[2].value;
+ MemW2(value, val0);
+ break;
+ case op_astoreb:
+ value = inst[0].value;
+ value += inst[1].value;
+ val0 = inst[2].value;
+ MemW1(value, val0);
+ break;
+ case op_astorebit:
+ value = inst[0].value;
+ vals0 = inst[1].value;
+ val1 = (vals0 & 7);
+ if (vals0 >= 0)
+ value += (vals0 >> 3);
+ else
+ value -= (1 + ((-1 - vals0) >> 3));
+ val0 = Mem1(value);
+ if (inst[2].value)
+ val0 |= (1 << val1);
+ else
+ val0 &= ~((uint)(1 << val1));
+ MemW1(value, val0);
+ break;
+
+ case op_stkcount:
+ value = (stackptr - valstackbase) / 4;
+ store_operand(inst[0].desttype, inst[0].value, value);
+ break;
+ case op_stkpeek:
+ vals0 = inst[0].value * 4;
+ if (vals0 < 0 || vals0 >= (int)(stackptr - valstackbase))
+ fatal_error("Stkpeek outside current stack range.");
+ value = Stk4(stackptr - (vals0 + 4));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_stkswap:
+ if (stackptr < valstackbase + 8) {
+ fatal_error("Stack underflow in stkswap.");
+ }
+ val0 = Stk4(stackptr - 4);
+ val1 = Stk4(stackptr - 8);
+ StkW4(stackptr - 4, val1);
+ StkW4(stackptr - 8, val0);
+ break;
+ case op_stkcopy:
+ vals0 = inst[0].value;
+ if (vals0 < 0)
+ fatal_error("Negative operand in stkcopy.");
+ if (vals0 == 0)
+ break;
+ if (stackptr < valstackbase + vals0 * 4)
+ fatal_error("Stack underflow in stkcopy.");
+ if (stackptr + vals0 * 4 > stacksize)
+ fatal_error("Stack overflow in stkcopy.");
+ addr = stackptr - vals0 * 4;
+ for (ix = 0; ix < vals0; ix++) {
+ value = Stk4(addr + ix * 4);
+ StkW4(stackptr + ix * 4, value);
+ }
+ stackptr += vals0 * 4;
+ break;
+ case op_stkroll:
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
+ if (vals0 < 0)
+ fatal_error("Negative operand in stkroll.");
+ if (stackptr < valstackbase + vals0 * 4)
+ fatal_error("Stack underflow in stkroll.");
+ if (vals0 == 0)
+ break;
+ /* The following is a bit ugly. We want to do vals1 = vals0-vals1,
+ because rolling down is sort of easier than rolling up. But
+ we also want to take the result mod vals0. The % operator is
+ annoying for negative numbers, so we need to do this in two
+ cases. */
+ if (vals1 > 0) {
+ vals1 = vals1 % vals0;
+ vals1 = (vals0) - vals1;
+ } else {
+ vals1 = (-vals1) % vals0;
+ }
+ if (vals1 == 0)
+ break;
+ addr = stackptr - vals0 * 4;
+ for (ix = 0; ix < vals1; ix++) {
+ value = Stk4(addr + ix * 4);
+ StkW4(stackptr + ix * 4, value);
+ }
+ for (ix = 0; ix < vals0; ix++) {
+ value = Stk4(addr + (vals1 + ix) * 4);
+ StkW4(addr + ix * 4, value);
+ }
+ break;
+
+ case op_streamchar:
+ profile_in(0xE0000001, stackptr, false);
+ value = inst[0].value & 0xFF;
+ (this->*stream_char_handler)(value);
+ profile_out(stackptr);
+ break;
+ case op_streamunichar:
+ profile_in(0xE0000002, stackptr, false);
+ value = inst[0].value;
+ (this->*stream_unichar_handler)(value);
+ profile_out(stackptr);
+ break;
+ case op_streamnum:
+ profile_in(0xE0000003, stackptr, false);
+ vals0 = inst[0].value;
+ stream_num(vals0, false, 0);
+ profile_out(stackptr);
+ break;
+ case op_streamstr:
+ profile_in(0xE0000004, stackptr, false);
+ stream_string(inst[0].value, 0, 0);
+ profile_out(stackptr);
+ break;
+
+ default:
+ fatal_error_i("Executed unknown opcode.", opcode);
+ }
+ } else {
+
+ switch (opcode) {
+
+ case op_gestalt:
+ value = do_gestalt(inst[0].value, inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+
+ case op_debugtrap:
#if VM_DEBUGGER
- /* We block and handle debug commands, but only if the
- library has invoked debug features. (Meaning, has
- the cycle handler ever been called.) */
- if (debugger_ever_invoked()) {
- debugger_block_and_debug("user debugtrap, pausing...");
- break;
- }
+ /* We block and handle debug commands, but only if the
+ library has invoked debug features. (Meaning, has
+ the cycle handler ever been called.) */
+ if (debugger_ever_invoked()) {
+ debugger_block_and_debug("user debugtrap, pausing...");
+ break;
+ }
#endif /* VM_DEBUGGER */
- fatal_error_i("user debugtrap encountered.", inst[0].value);
-
- case op_jumpabs:
- pc = inst[0].value;
- break;
-
- case op_callf:
- push_callstub(inst[1].desttype, inst[1].value);
- enter_function(inst[0].value, 0, arglistfix);
- break;
- case op_callfi:
- arglistfix[0] = inst[1].value;
- push_callstub(inst[2].desttype, inst[2].value);
- enter_function(inst[0].value, 1, arglistfix);
- break;
- case op_callfii:
- arglistfix[0] = inst[1].value;
- arglistfix[1] = inst[2].value;
- push_callstub(inst[3].desttype, inst[3].value);
- enter_function(inst[0].value, 2, arglistfix);
- break;
- case op_callfiii:
- arglistfix[0] = inst[1].value;
- arglistfix[1] = inst[2].value;
- arglistfix[2] = inst[3].value;
- push_callstub(inst[4].desttype, inst[4].value);
- enter_function(inst[0].value, 3, arglistfix);
- break;
-
- case op_getmemsize:
- store_operand(inst[0].desttype, inst[0].value, endmem);
- break;
- case op_setmemsize:
- value = change_memsize(inst[0].value, false);
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
-
- case op_getstringtbl:
- value = stream_get_table();
- store_operand(inst[0].desttype, inst[0].value, value);
- break;
- case op_setstringtbl:
- stream_set_table(inst[0].value);
- break;
-
- case op_getiosys:
- stream_get_iosys(&val0, &val1);
- store_operand(inst[0].desttype, inst[0].value, val0);
- store_operand(inst[1].desttype, inst[1].value, val1);
- break;
- case op_setiosys:
- stream_set_iosys(inst[0].value, inst[1].value);
- break;
-
- case op_glk:
- profile_in(0xF0000000+inst[0].value, stackptr, false);
- value = inst[1].value;
- arglist = pop_arguments(value, 0);
- val0 = perform_glk(inst[0].value, value, arglist);
+ fatal_error_i("user debugtrap encountered.", inst[0].value);
+
+ case op_jumpabs:
+ pc = inst[0].value;
+ break;
+
+ case op_callf:
+ push_callstub(inst[1].desttype, inst[1].value);
+ enter_function(inst[0].value, 0, arglistfix);
+ break;
+ case op_callfi:
+ arglistfix[0] = inst[1].value;
+ push_callstub(inst[2].desttype, inst[2].value);
+ enter_function(inst[0].value, 1, arglistfix);
+ break;
+ case op_callfii:
+ arglistfix[0] = inst[1].value;
+ arglistfix[1] = inst[2].value;
+ push_callstub(inst[3].desttype, inst[3].value);
+ enter_function(inst[0].value, 2, arglistfix);
+ break;
+ case op_callfiii:
+ arglistfix[0] = inst[1].value;
+ arglistfix[1] = inst[2].value;
+ arglistfix[2] = inst[3].value;
+ push_callstub(inst[4].desttype, inst[4].value);
+ enter_function(inst[0].value, 3, arglistfix);
+ break;
+
+ case op_getmemsize:
+ store_operand(inst[0].desttype, inst[0].value, endmem);
+ break;
+ case op_setmemsize:
+ value = change_memsize(inst[0].value, false);
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+
+ case op_getstringtbl:
+ value = stream_get_table();
+ store_operand(inst[0].desttype, inst[0].value, value);
+ break;
+ case op_setstringtbl:
+ stream_set_table(inst[0].value);
+ break;
+
+ case op_getiosys:
+ stream_get_iosys(&val0, &val1);
+ store_operand(inst[0].desttype, inst[0].value, val0);
+ store_operand(inst[1].desttype, inst[1].value, val1);
+ break;
+ case op_setiosys:
+ stream_set_iosys(inst[0].value, inst[1].value);
+ break;
+
+ case op_glk:
+ profile_in(0xF0000000 + inst[0].value, stackptr, false);
+ value = inst[1].value;
+ arglist = pop_arguments(value, 0);
+ val0 = perform_glk(inst[0].value, value, arglist);
#ifdef TOLERATE_SUPERGLUS_BUG
- if (inst[2].desttype == 1 && inst[2].value == 0)
- inst[2].desttype = 0;
+ if (inst[2].desttype == 1 && inst[2].value == 0)
+ inst[2].desttype = 0;
#endif /* TOLERATE_SUPERGLUS_BUG */
- store_operand(inst[2].desttype, inst[2].value, val0);
- profile_out(stackptr);
- break;
-
- case op_random:
- vals0 = inst[0].value;
- if (vals0 == 0)
- value = glulx_random();
- else if (vals0 >= 1)
- value = glulx_random() % (uint)(vals0);
- else
- value = -(int)(glulx_random() % (uint)(-vals0));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_setrandom:
- glulx_setrandom(inst[0].value);
- break;
-
- case op_verify:
- value = perform_verify();
- store_operand(inst[0].desttype, inst[0].value, value);
- break;
-
- case op_restart:
- profile_fail("restart");
- vm_restart();
- break;
-
- case op_protect:
- val0 = inst[0].value;
- val1 = val0 + inst[1].value;
- if (val0 == val1) {
- val0 = 0;
- val1 = 0;
- }
- protectstart = val0;
- protectend = val1;
- break;
-
- case op_save:
- push_callstub(inst[1].desttype, inst[1].value);
- value = perform_save(find_stream_by_id(inst[0].value));
- pop_callstub(value);
- break;
-
- case op_restore:
- value = perform_restore(find_stream_by_id(inst[0].value), false);
- if (value == 0) {
- /* We've succeeded, and the stack now contains the callstub
- saved during saveundo. Ignore this opcode's operand. */
- value = (uint)-1;
- pop_callstub(value);
- }
- else {
- /* We've failed, so we must store the failure in this opcode's
- operand. */
- store_operand(inst[1].desttype, inst[1].value, value);
- }
- break;
-
- case op_saveundo:
- push_callstub(inst[0].desttype, inst[0].value);
- value = perform_saveundo();
- pop_callstub(value);
- break;
-
- case op_restoreundo:
- value = perform_restoreundo();
- if (value == 0) {
- /* We've succeeded, and the stack now contains the callstub
- saved during saveundo. Ignore this opcode's operand. */
- value = (uint)-1;
- pop_callstub(value);
- }
- else {
- /* We've failed, so we must store the failure in this opcode's
- operand. */
- store_operand(inst[0].desttype, inst[0].value, value);
- }
- break;
-
- case op_quit:
- done_executing = true;
- break;
-
- case op_linearsearch:
- value = linear_search(inst[0].value, inst[1].value, inst[2].value,
- inst[3].value, inst[4].value, inst[5].value, inst[6].value);
- store_operand(inst[7].desttype, inst[7].value, value);
- break;
- case op_binarysearch:
- value = binary_search(inst[0].value, inst[1].value, inst[2].value,
- inst[3].value, inst[4].value, inst[5].value, inst[6].value);
- store_operand(inst[7].desttype, inst[7].value, value);
- break;
- case op_linkedsearch:
- value = linked_search(inst[0].value, inst[1].value, inst[2].value,
- inst[3].value, inst[4].value, inst[5].value);
- store_operand(inst[6].desttype, inst[6].value, value);
- break;
-
- case op_mzero: {
- uint lx;
- uint count = inst[0].value;
- addr = inst[1].value;
- for (lx=0; lx<count; lx++, addr++) {
- MemW1(addr, 0);
- }
- }
- break;
- case op_mcopy: {
- uint lx;
- uint count = inst[0].value;
- uint addrsrc = inst[1].value;
- uint addrdest = inst[2].value;
- if (addrdest < addrsrc) {
- for (lx=0; lx<count; lx++, addrsrc++, addrdest++) {
- value = Mem1(addrsrc);
- MemW1(addrdest, value);
- }
- }
- else {
- addrsrc += (count-1);
- addrdest += (count-1);
- for (lx=0; lx<count; lx++, addrsrc--, addrdest--) {
- value = Mem1(addrsrc);
- MemW1(addrdest, value);
- }
- }
- }
- break;
- case op_malloc:
- value = heap_alloc(inst[0].value);
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_mfree:
- heap_free(inst[0].value);
- break;
-
- case op_accelfunc:
- accel_set_func(inst[0].value, inst[1].value);
- break;
- case op_accelparam:
- accel_set_param(inst[0].value, inst[1].value);
- break;
+ store_operand(inst[2].desttype, inst[2].value, val0);
+ profile_out(stackptr);
+ break;
+
+ case op_random:
+ vals0 = inst[0].value;
+ if (vals0 == 0)
+ value = glulx_random();
+ else if (vals0 >= 1)
+ value = glulx_random() % (uint)(vals0);
+ else
+ value = -(int)(glulx_random() % (uint)(-vals0));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_setrandom:
+ glulx_setrandom(inst[0].value);
+ break;
+
+ case op_verify:
+ value = perform_verify();
+ store_operand(inst[0].desttype, inst[0].value, value);
+ break;
+
+ case op_restart:
+ profile_fail("restart");
+ vm_restart();
+ break;
+
+ case op_protect:
+ val0 = inst[0].value;
+ val1 = val0 + inst[1].value;
+ if (val0 == val1) {
+ val0 = 0;
+ val1 = 0;
+ }
+ protectstart = val0;
+ protectend = val1;
+ break;
+
+ case op_save:
+ push_callstub(inst[1].desttype, inst[1].value);
+ value = perform_save(find_stream_by_id(inst[0].value));
+ pop_callstub(value);
+ break;
+
+ case op_restore:
+ value = perform_restore(find_stream_by_id(inst[0].value), false);
+ if (value == 0) {
+ /* We've succeeded, and the stack now contains the callstub
+ saved during saveundo. Ignore this opcode's operand. */
+ value = (uint) - 1;
+ pop_callstub(value);
+ } else {
+ /* We've failed, so we must store the failure in this opcode's
+ operand. */
+ store_operand(inst[1].desttype, inst[1].value, value);
+ }
+ break;
+
+ case op_saveundo:
+ push_callstub(inst[0].desttype, inst[0].value);
+ value = perform_saveundo();
+ pop_callstub(value);
+ break;
+
+ case op_restoreundo:
+ value = perform_restoreundo();
+ if (value == 0) {
+ /* We've succeeded, and the stack now contains the callstub
+ saved during saveundo. Ignore this opcode's operand. */
+ value = (uint) - 1;
+ pop_callstub(value);
+ } else {
+ /* We've failed, so we must store the failure in this opcode's
+ operand. */
+ store_operand(inst[0].desttype, inst[0].value, value);
+ }
+ break;
+
+ case op_quit:
+ done_executing = true;
+ break;
+
+ case op_linearsearch:
+ value = linear_search(inst[0].value, inst[1].value, inst[2].value,
+ inst[3].value, inst[4].value, inst[5].value, inst[6].value);
+ store_operand(inst[7].desttype, inst[7].value, value);
+ break;
+ case op_binarysearch:
+ value = binary_search(inst[0].value, inst[1].value, inst[2].value,
+ inst[3].value, inst[4].value, inst[5].value, inst[6].value);
+ store_operand(inst[7].desttype, inst[7].value, value);
+ break;
+ case op_linkedsearch:
+ value = linked_search(inst[0].value, inst[1].value, inst[2].value,
+ inst[3].value, inst[4].value, inst[5].value);
+ store_operand(inst[6].desttype, inst[6].value, value);
+ break;
+
+ case op_mzero: {
+ uint lx;
+ uint count = inst[0].value;
+ addr = inst[1].value;
+ for (lx = 0; lx < count; lx++, addr++) {
+ MemW1(addr, 0);
+ }
+ }
+ break;
+ case op_mcopy: {
+ uint lx;
+ uint count = inst[0].value;
+ uint addrsrc = inst[1].value;
+ uint addrdest = inst[2].value;
+ if (addrdest < addrsrc) {
+ for (lx = 0; lx < count; lx++, addrsrc++, addrdest++) {
+ value = Mem1(addrsrc);
+ MemW1(addrdest, value);
+ }
+ } else {
+ addrsrc += (count - 1);
+ addrdest += (count - 1);
+ for (lx = 0; lx < count; lx++, addrsrc--, addrdest--) {
+ value = Mem1(addrsrc);
+ MemW1(addrdest, value);
+ }
+ }
+ }
+ break;
+ case op_malloc:
+ value = heap_alloc(inst[0].value);
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_mfree:
+ heap_free(inst[0].value);
+ break;
+
+ case op_accelfunc:
+ accel_set_func(inst[0].value, inst[1].value);
+ break;
+ case op_accelparam:
+ accel_set_param(inst[0].value, inst[1].value);
+ break;
#ifdef FLOAT_SUPPORT
- case op_numtof:
- vals0 = inst[0].value;
- value = encode_float((gfloat32)vals0);
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_ftonumz:
- valf = decode_float(inst[0].value);
- if (!signbit(valf)) {
- if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
- vals0 = 0x7FFFFFFF;
- else
- vals0 = (int)(truncf(valf));
- }
- else {
- if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
- vals0 = 0x80000000;
- else
- vals0 = (int)(truncf(valf));
- }
- store_operand(inst[1].desttype, inst[1].value, vals0);
- break;
- case op_ftonumn:
- valf = decode_float(inst[0].value);
- if (!signbit(valf)) {
- if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
- vals0 = 0x7FFFFFFF;
- else
- vals0 = (int)(roundf(valf));
- }
- else {
- if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
- vals0 = 0x80000000;
- else
- vals0 = (int)(roundf(valf));
- }
- store_operand(inst[1].desttype, inst[1].value, vals0);
- break;
-
- case op_fadd:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- value = encode_float(valf1 + valf2);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_fsub:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- value = encode_float(valf1 - valf2);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_fmul:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- value = encode_float(valf1 * valf2);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
- case op_fdiv:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- value = encode_float(valf1 / valf2);
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
-
- case op_fmod:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- valf = fmodf(valf1, valf2);
- val0 = encode_float(valf);
- val1 = encode_float((valf1-valf) / valf2);
- if (val1 == 0x0 || val1 == 0x80000000) {
- /* When the quotient is zero, the sign has been lost in the
- shuffle. We'll set that by hand, based on the original
- arguments. */
- val1 = (inst[0].value ^ inst[1].value) & 0x80000000;
- }
- store_operand(inst[2].desttype, inst[2].value, val0);
- store_operand(inst[3].desttype, inst[3].value, val1);
- break;
-
- case op_floor:
- valf = decode_float(inst[0].value);
- value = encode_float(floorf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_ceil:
- valf = decode_float(inst[0].value);
- value = encode_float(ceilf(valf));
- if (value == 0x0 || value == 0x80000000) {
- /* When the result is zero, the sign may have been lost in the
- shuffle. (This is a bug in some C libraries.) We'll set the
- sign by hand, based on the original argument. */
- value = inst[0].value & 0x80000000;
- }
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
-
- case op_sqrt:
- valf = decode_float(inst[0].value);
- value = encode_float(sqrtf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_log:
- valf = decode_float(inst[0].value);
- value = encode_float(logf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_exp:
- valf = decode_float(inst[0].value);
- value = encode_float(expf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_pow:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- value = encode_float(glulx_powf(valf1, valf2));
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
-
- case op_sin:
- valf = decode_float(inst[0].value);
- value = encode_float(sinf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_cos:
- valf = decode_float(inst[0].value);
- value = encode_float(cosf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_tan:
- valf = decode_float(inst[0].value);
- value = encode_float(tanf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_asin:
- valf = decode_float(inst[0].value);
- value = encode_float(asinf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_acos:
- valf = decode_float(inst[0].value);
- value = encode_float(acosf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_atan:
- valf = decode_float(inst[0].value);
- value = encode_float(atanf(valf));
- store_operand(inst[1].desttype, inst[1].value, value);
- break;
- case op_atan2:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- value = encode_float(atan2f(valf1, valf2));
- store_operand(inst[2].desttype, inst[2].value, value);
- break;
-
- case op_jisinf:
- /* Infinity is well-defined, so we don't bother to convert to
- float. */
- val0 = inst[0].value;
- if (val0 == 0x7F800000 || val0 == 0xFF800000) {
- value = inst[1].value;
- goto PerformJump;
- }
- break;
- case op_jisnan:
- /* NaN is well-defined, so we don't bother to convert to
- float. */
- val0 = inst[0].value;
- if ((val0 & 0x7F800000) == 0x7F800000 && (val0 & 0x007FFFFF) != 0) {
- value = inst[1].value;
- goto PerformJump;
- }
- break;
-
- case op_jfeq:
- if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
- /* The delta is NaN, which can never match. */
- val0 = 0;
- }
- else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
- && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
- /* Both are infinite. Opposite infinities are never equal,
- even if the difference is infinite, so this is easy. */
- val0 = (inst[0].value == inst[1].value);
- }
- else {
- valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
- valf2 = fabs(decode_float(inst[2].value));
- val0 = (valf1 <= valf2 && valf1 >= -valf2);
- }
- if (val0) {
- value = inst[3].value;
- goto PerformJump;
- }
- break;
- case op_jfne:
- if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
- /* The delta is NaN, which can never match. */
- val0 = 0;
- }
- else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
- && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
- /* Both are infinite. Opposite infinities are never equal,
- even if the difference is infinite, so this is easy. */
- val0 = (inst[0].value == inst[1].value);
- }
- else {
- valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
- valf2 = fabs(decode_float(inst[2].value));
- val0 = (valf1 <= valf2 && valf1 >= -valf2);
- }
- if (!val0) {
- value = inst[3].value;
- goto PerformJump;
- }
- break;
-
- case op_jflt:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- if (valf1 < valf2) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jfgt:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- if (valf1 > valf2) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jfle:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- if (valf1 <= valf2) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
- case op_jfge:
- valf1 = decode_float(inst[0].value);
- valf2 = decode_float(inst[1].value);
- if (valf1 >= valf2) {
- value = inst[2].value;
- goto PerformJump;
- }
- break;
+ case op_numtof:
+ vals0 = inst[0].value;
+ value = encode_float((gfloat32)vals0);
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_ftonumz:
+ valf = decode_float(inst[0].value);
+ if (!signbit(valf)) {
+ if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
+ vals0 = 0x7FFFFFFF;
+ else
+ vals0 = (int)(truncf(valf));
+ } else {
+ if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
+ vals0 = 0x80000000;
+ else
+ vals0 = (int)(truncf(valf));
+ }
+ store_operand(inst[1].desttype, inst[1].value, vals0);
+ break;
+ case op_ftonumn:
+ valf = decode_float(inst[0].value);
+ if (!signbit(valf)) {
+ if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
+ vals0 = 0x7FFFFFFF;
+ else
+ vals0 = (int)(roundf(valf));
+ } else {
+ if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
+ vals0 = 0x80000000;
+ else
+ vals0 = (int)(roundf(valf));
+ }
+ store_operand(inst[1].desttype, inst[1].value, vals0);
+ break;
+
+ case op_fadd:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ value = encode_float(valf1 + valf2);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_fsub:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ value = encode_float(valf1 - valf2);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_fmul:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ value = encode_float(valf1 * valf2);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+ case op_fdiv:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ value = encode_float(valf1 / valf2);
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+
+ case op_fmod:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ valf = fmodf(valf1, valf2);
+ val0 = encode_float(valf);
+ val1 = encode_float((valf1 - valf) / valf2);
+ if (val1 == 0x0 || val1 == 0x80000000) {
+ /* When the quotient is zero, the sign has been lost in the
+ shuffle. We'll set that by hand, based on the original
+ arguments. */
+ val1 = (inst[0].value ^ inst[1].value) & 0x80000000;
+ }
+ store_operand(inst[2].desttype, inst[2].value, val0);
+ store_operand(inst[3].desttype, inst[3].value, val1);
+ break;
+
+ case op_floor:
+ valf = decode_float(inst[0].value);
+ value = encode_float(floorf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_ceil:
+ valf = decode_float(inst[0].value);
+ value = encode_float(ceilf(valf));
+ if (value == 0x0 || value == 0x80000000) {
+ /* When the result is zero, the sign may have been lost in the
+ shuffle. (This is a bug in some C libraries.) We'll set the
+ sign by hand, based on the original argument. */
+ value = inst[0].value & 0x80000000;
+ }
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+
+ case op_sqrt:
+ valf = decode_float(inst[0].value);
+ value = encode_float(sqrtf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_log:
+ valf = decode_float(inst[0].value);
+ value = encode_float(logf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_exp:
+ valf = decode_float(inst[0].value);
+ value = encode_float(expf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_pow:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ value = encode_float(glulx_powf(valf1, valf2));
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+
+ case op_sin:
+ valf = decode_float(inst[0].value);
+ value = encode_float(sinf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_cos:
+ valf = decode_float(inst[0].value);
+ value = encode_float(cosf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_tan:
+ valf = decode_float(inst[0].value);
+ value = encode_float(tanf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_asin:
+ valf = decode_float(inst[0].value);
+ value = encode_float(asinf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_acos:
+ valf = decode_float(inst[0].value);
+ value = encode_float(acosf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_atan:
+ valf = decode_float(inst[0].value);
+ value = encode_float(atanf(valf));
+ store_operand(inst[1].desttype, inst[1].value, value);
+ break;
+ case op_atan2:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ value = encode_float(atan2f(valf1, valf2));
+ store_operand(inst[2].desttype, inst[2].value, value);
+ break;
+
+ case op_jisinf:
+ /* Infinity is well-defined, so we don't bother to convert to
+ float. */
+ val0 = inst[0].value;
+ if (val0 == 0x7F800000 || val0 == 0xFF800000) {
+ value = inst[1].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jisnan:
+ /* NaN is well-defined, so we don't bother to convert to
+ float. */
+ val0 = inst[0].value;
+ if ((val0 & 0x7F800000) == 0x7F800000 && (val0 & 0x007FFFFF) != 0) {
+ value = inst[1].value;
+ goto PerformJump;
+ }
+ break;
+
+ case op_jfeq:
+ if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
+ /* The delta is NaN, which can never match. */
+ val0 = 0;
+ } else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
+ && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
+ /* Both are infinite. Opposite infinities are never equal,
+ even if the difference is infinite, so this is easy. */
+ val0 = (inst[0].value == inst[1].value);
+ } else {
+ valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
+ valf2 = fabs(decode_float(inst[2].value));
+ val0 = (valf1 <= valf2 && valf1 >= -valf2);
+ }
+ if (val0) {
+ value = inst[3].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jfne:
+ if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
+ /* The delta is NaN, which can never match. */
+ val0 = 0;
+ } else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
+ && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
+ /* Both are infinite. Opposite infinities are never equal,
+ even if the difference is infinite, so this is easy. */
+ val0 = (inst[0].value == inst[1].value);
+ } else {
+ valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
+ valf2 = fabs(decode_float(inst[2].value));
+ val0 = (valf1 <= valf2 && valf1 >= -valf2);
+ }
+ if (!val0) {
+ value = inst[3].value;
+ goto PerformJump;
+ }
+ break;
+
+ case op_jflt:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ if (valf1 < valf2) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jfgt:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ if (valf1 > valf2) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jfle:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ if (valf1 <= valf2) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jfge:
+ valf1 = decode_float(inst[0].value);
+ valf2 = decode_float(inst[1].value);
+ if (valf1 >= valf2) {
+ value = inst[2].value;
+ goto PerformJump;
+ }
+ break;
#endif /* FLOAT_SUPPORT */
#ifdef GLULX_EXTEND_OPCODES
- GLULX_EXTEND_OPCODES
+ GLULX_EXTEND_OPCODES
#endif /* GLULX_EXTEND_OPCODES */
- default:
- fatal_error_i("Executed unknown opcode.", opcode);
- }
- }
- }
- /* done executing */
+ default:
+ fatal_error_i("Executed unknown opcode.", opcode);
+ }
+ }
+ }
+ /* done executing */
#if VM_DEBUGGER
- debugger_handle_quit();
+ debugger_handle_quit();
#endif /* VM_DEBUGGER */
}
diff --git a/engines/glk/glulxe/float.cpp b/engines/glk/glulxe/float.cpp
index 36ef2f479b..c978ef9c7f 100644
--- a/engines/glk/glulxe/float.cpp
+++ b/engines/glk/glulxe/float.cpp
@@ -26,104 +26,97 @@ namespace Glk {
namespace Glulxe {
uint Glulxe::encode_float(gfloat32 val) {
- gfloat32 absval;
- uint sign;
- int expo;
- gfloat32 mant;
- uint fbits;
-
- if (signbit(val)) {
- sign = 0x80000000;
- absval = -val;
- }
- else {
- sign = 0x0;
- absval = val;
- }
-
- if (isinf(val)) {
- return sign | 0x7f800000; /* infinity */
- }
-
- if (isnan(val)) {
- return sign | 0x7fc00000;
- }
-
- mant = frexpf(absval, &expo);
-
- /* Normalize mantissa to be in the range [1.0, 2.0) */
- if (0.5 <= mant && mant < 1.0) {
- mant *= 2.0;
- expo--;
- }
- else if (mant == 0.0) {
- expo = 0;
- }
- else {
- return sign | 0x7f800000; /* infinity */
- }
-
- if (expo >= 128) {
- return sign | 0x7f800000; /* infinity */
- }
- else if (expo < -126) {
- /* Denormalized (very small) number */
- mant = ldexpf(mant, 126 + expo);
- expo = 0;
- }
- else if (!(expo == 0 && mant == 0.0)) {
- expo += 127;
- mant -= 1.0; /* Get rid of leading 1 */
- }
-
- mant *= 8388608.0; /* 2^23 */
- fbits = (uint)(mant + 0.5); /* round mant to nearest int */
- if (fbits >> 23) {
- /* The carry propagated out of a string of 23 1 bits. */
- fbits = 0;
- expo++;
- if (expo >= 255) {
- return sign | 0x7f800000; /* infinity */
- }
- }
-
- return (sign) | ((uint)(expo << 23)) | (fbits);
+ gfloat32 absval;
+ uint sign;
+ int expo;
+ gfloat32 mant;
+ uint fbits;
+
+ if (signbit(val)) {
+ sign = 0x80000000;
+ absval = -val;
+ } else {
+ sign = 0x0;
+ absval = val;
+ }
+
+ if (isinf(val)) {
+ return sign | 0x7f800000; /* infinity */
+ }
+
+ if (isnan(val)) {
+ return sign | 0x7fc00000;
+ }
+
+ mant = frexpf(absval, &expo);
+
+ /* Normalize mantissa to be in the range [1.0, 2.0) */
+ if (0.5 <= mant && mant < 1.0) {
+ mant *= 2.0;
+ expo--;
+ } else if (mant == 0.0) {
+ expo = 0;
+ } else {
+ return sign | 0x7f800000; /* infinity */
+ }
+
+ if (expo >= 128) {
+ return sign | 0x7f800000; /* infinity */
+ } else if (expo < -126) {
+ /* Denormalized (very small) number */
+ mant = ldexpf(mant, 126 + expo);
+ expo = 0;
+ } else if (!(expo == 0 && mant == 0.0)) {
+ expo += 127;
+ mant -= 1.0; /* Get rid of leading 1 */
+ }
+
+ mant *= 8388608.0; /* 2^23 */
+ fbits = (uint)(mant + 0.5); /* round mant to nearest int */
+ if (fbits >> 23) {
+ /* The carry propagated out of a string of 23 1 bits. */
+ fbits = 0;
+ expo++;
+ if (expo >= 255) {
+ return sign | 0x7f800000; /* infinity */
+ }
+ }
+
+ return (sign) | ((uint)(expo << 23)) | (fbits);
}
gfloat32 Glulxe::decode_float(uint val) {
- int sign;
- int expo;
- uint mant;
- gfloat32 res;
-
- /* First byte */
- sign = ((val & 0x80000000) != 0);
- expo = (val >> 23) & 0xFF;
- mant = val & 0x7FFFFF;
-
- if (expo == 255) {
- if (mant == 0) {
- /* Infinity */
- return (sign ? (-INFINITY) : (INFINITY));
- }
- else {
- /* Not a number */
- return (sign ? (-NAN) : (NAN));
- }
- }
-
- res = (gfloat32)mant / 8388608.0;
-
- if (expo == 0) {
- expo = -126;
- }
- else {
- res += 1.0;
- expo -= 127;
- }
- res = ldexpf(res, expo);
-
- return (sign ? (-res) : (res));
+ int sign;
+ int expo;
+ uint mant;
+ gfloat32 res;
+
+ /* First byte */
+ sign = ((val & 0x80000000) != 0);
+ expo = (val >> 23) & 0xFF;
+ mant = val & 0x7FFFFF;
+
+ if (expo == 255) {
+ if (mant == 0) {
+ /* Infinity */
+ return (sign ? (-INFINITY) : (INFINITY));
+ } else {
+ /* Not a number */
+ return (sign ? (-NAN) : (NAN));
+ }
+ }
+
+ res = (gfloat32)mant / 8388608.0;
+
+ if (expo == 0) {
+ expo = -126;
+ } else {
+ res += 1.0;
+ expo -= 127;
+ }
+ res = ldexpf(res, expo);
+
+ return (sign ? (-res) : (res));
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/funcs.cpp b/engines/glk/glulxe/funcs.cpp
index b85844a8c1..4af52630a3 100644
--- a/engines/glk/glulxe/funcs.cpp
+++ b/engines/glk/glulxe/funcs.cpp
@@ -26,279 +26,273 @@ namespace Glk {
namespace Glulxe {
void Glulxe::enter_function(uint funcaddr, uint argc, uint *argv) {
- uint ix, jx;
- acceleration_func accelFunc;
- int locallen;
- int functype;
- uint modeaddr, opaddr, val;
- int loctype, locnum;
- uint addr = funcaddr;
-
- accelFunc = accel_get_func(addr);
- if (accelFunc) {
- profile_in(addr, stackptr, TRUE);
- val = (this->*accelFunc)(argc, argv);
- profile_out(stackptr);
- pop_callstub(val);
- return;
- }
-
- profile_in(addr, stackptr, FALSE);
-
- /* Check the Glulx type identifier byte. */
- functype = Mem1(addr);
- if (functype != 0xC0 && functype != 0xC1) {
- if (functype >= 0xC0 && functype <= 0xDF)
- fatal_error_i("Call to unknown type of function.", addr);
- else
- fatal_error_i("Call to non-function.", addr);
- }
- addr++;
-
- /* Bump the frameptr to the top. */
- frameptr = stackptr;
-
- /* Go through the function's locals-format list, copying it to the
- call frame. At the same time, we work out how much space the locals
- will actually take up. (Including padding.) */
- ix = 0;
- locallen = 0;
- while (1) {
- /* Grab two bytes from the locals-format list. These are
- unsigned (0..255 range). */
- loctype = Mem1(addr);
- addr++;
- locnum = Mem1(addr);
- addr++;
-
- /* Copy them into the call frame. */
- StkW1(frameptr+8+2*ix, loctype);
- StkW1(frameptr+8+2*ix+1, locnum);
- ix++;
-
- /* If the type is zero, we're done, except possibly for two more
- zero bytes in the call frame (to ensure 4-byte alignment.) */
- if (loctype == 0) {
- /* Make sure ix is even. */
- if (ix & 1) {
- StkW1(frameptr+8+2*ix, 0);
- StkW1(frameptr+8+2*ix+1, 0);
- ix++;
- }
- break;
- }
-
- /* Pad to 4-byte or 2-byte alignment if these locals are 4 or 2
- bytes long. */
- if (loctype == 4) {
- while (locallen & 3)
- locallen++;
- }
- else if (loctype == 2) {
- while (locallen & 1)
- locallen++;
- }
- else if (loctype == 1) {
- /* no padding */
- }
- else {
- fatal_error("Illegal local type in locals-format list.");
- }
-
- /* Add the length of the locals themselves. */
- locallen += (loctype * locnum);
- }
-
- /* Pad the locals to 4-byte alignment. */
- while (locallen & 3)
- locallen++;
-
- /* We now know how long the locals-frame and locals segments are. */
- localsbase = frameptr+8+2*ix;
- valstackbase = localsbase+locallen;
-
- /* Test for stack overflow. */
- /* This really isn't good enough; if the format list overflowed the
- stack, we've already written outside the stack array. */
- if (valstackbase >= stacksize)
- fatal_error("Stack overflow in function call.");
-
- /* Fill in the beginning of the stack frame. */
- StkW4(frameptr+4, 8+2*ix);
- StkW4(frameptr, 8+2*ix+locallen);
-
- /* Set the stackptr and PC. */
- stackptr = valstackbase;
- pc = addr;
-
- /* Zero out all the locals. */
- for (jx=0; jx < (uint)locallen; jx++)
- StkW1(localsbase+jx, 0);
-
- if (functype == 0xC0) {
- /* Push the function arguments on the stack. The locals have already
- been zeroed. */
- if (stackptr+4*(argc+1) >= stacksize)
- fatal_error("Stack overflow in function arguments.");
- for (ix=0; ix<argc; ix++) {
- val = argv[(argc-1)-ix];
- StkW4(stackptr, val);
- stackptr += 4;
- }
- StkW4(stackptr, argc);
- stackptr += 4;
- }
- else {
- /* Copy in function arguments. This is a bit gross, since we have to
- follow the locals format. If there are fewer arguments than locals,
- that's fine -- we've already zeroed out this space. If there are
- more arguments than locals, the extras are silently dropped. */
- modeaddr = frameptr+8;
- opaddr = localsbase;
- ix = 0;
- while (ix < argc) {
- loctype = Stk1(modeaddr);
- modeaddr++;
- locnum = Stk1(modeaddr);
- modeaddr++;
- if (loctype == 0)
- break;
- if (loctype == 4) {
- while (opaddr & 3)
- opaddr++;
- while (ix < argc && locnum) {
- val = argv[ix];
- StkW4(opaddr, val);
- opaddr += 4;
- ix++;
- locnum--;
- }
- }
- else if (loctype == 2) {
- while (opaddr & 1)
- opaddr++;
- while (ix < argc && locnum) {
- val = argv[ix] & 0xFFFF;
- StkW2(opaddr, val);
- opaddr += 2;
- ix++;
- locnum--;
- }
- }
- else if (loctype == 1) {
- while (ix < argc && locnum) {
- val = argv[ix] & 0xFF;
- StkW1(opaddr, val);
- opaddr += 1;
- ix++;
- locnum--;
- }
- }
- }
- }
-
- /* If the debugger is compiled in, check for a breakpoint on this
- function. (Checking the function address, not the starting PC.) */
- debugger_check_func_breakpoint(funcaddr);
+ uint ix, jx;
+ acceleration_func accelFunc;
+ int locallen;
+ int functype;
+ uint modeaddr, opaddr, val;
+ int loctype, locnum;
+ uint addr = funcaddr;
+
+ accelFunc = accel_get_func(addr);
+ if (accelFunc) {
+ profile_in(addr, stackptr, TRUE);
+ val = (this->*accelFunc)(argc, argv);
+ profile_out(stackptr);
+ pop_callstub(val);
+ return;
+ }
+
+ profile_in(addr, stackptr, FALSE);
+
+ /* Check the Glulx type identifier byte. */
+ functype = Mem1(addr);
+ if (functype != 0xC0 && functype != 0xC1) {
+ if (functype >= 0xC0 && functype <= 0xDF)
+ fatal_error_i("Call to unknown type of function.", addr);
+ else
+ fatal_error_i("Call to non-function.", addr);
+ }
+ addr++;
+
+ /* Bump the frameptr to the top. */
+ frameptr = stackptr;
+
+ /* Go through the function's locals-format list, copying it to the
+ call frame. At the same time, we work out how much space the locals
+ will actually take up. (Including padding.) */
+ ix = 0;
+ locallen = 0;
+ while (1) {
+ /* Grab two bytes from the locals-format list. These are
+ unsigned (0..255 range). */
+ loctype = Mem1(addr);
+ addr++;
+ locnum = Mem1(addr);
+ addr++;
+
+ /* Copy them into the call frame. */
+ StkW1(frameptr + 8 + 2 * ix, loctype);
+ StkW1(frameptr + 8 + 2 * ix + 1, locnum);
+ ix++;
+
+ /* If the type is zero, we're done, except possibly for two more
+ zero bytes in the call frame (to ensure 4-byte alignment.) */
+ if (loctype == 0) {
+ /* Make sure ix is even. */
+ if (ix & 1) {
+ StkW1(frameptr + 8 + 2 * ix, 0);
+ StkW1(frameptr + 8 + 2 * ix + 1, 0);
+ ix++;
+ }
+ break;
+ }
+
+ /* Pad to 4-byte or 2-byte alignment if these locals are 4 or 2
+ bytes long. */
+ if (loctype == 4) {
+ while (locallen & 3)
+ locallen++;
+ } else if (loctype == 2) {
+ while (locallen & 1)
+ locallen++;
+ } else if (loctype == 1) {
+ /* no padding */
+ } else {
+ fatal_error("Illegal local type in locals-format list.");
+ }
+
+ /* Add the length of the locals themselves. */
+ locallen += (loctype * locnum);
+ }
+
+ /* Pad the locals to 4-byte alignment. */
+ while (locallen & 3)
+ locallen++;
+
+ /* We now know how long the locals-frame and locals segments are. */
+ localsbase = frameptr + 8 + 2 * ix;
+ valstackbase = localsbase + locallen;
+
+ /* Test for stack overflow. */
+ /* This really isn't good enough; if the format list overflowed the
+ stack, we've already written outside the stack array. */
+ if (valstackbase >= stacksize)
+ fatal_error("Stack overflow in function call.");
+
+ /* Fill in the beginning of the stack frame. */
+ StkW4(frameptr + 4, 8 + 2 * ix);
+ StkW4(frameptr, 8 + 2 * ix + locallen);
+
+ /* Set the stackptr and PC. */
+ stackptr = valstackbase;
+ pc = addr;
+
+ /* Zero out all the locals. */
+ for (jx = 0; jx < (uint)locallen; jx++)
+ StkW1(localsbase + jx, 0);
+
+ if (functype == 0xC0) {
+ /* Push the function arguments on the stack. The locals have already
+ been zeroed. */
+ if (stackptr + 4 * (argc + 1) >= stacksize)
+ fatal_error("Stack overflow in function arguments.");
+ for (ix = 0; ix < argc; ix++) {
+ val = argv[(argc - 1) - ix];
+ StkW4(stackptr, val);
+ stackptr += 4;
+ }
+ StkW4(stackptr, argc);
+ stackptr += 4;
+ } else {
+ /* Copy in function arguments. This is a bit gross, since we have to
+ follow the locals format. If there are fewer arguments than locals,
+ that's fine -- we've already zeroed out this space. If there are
+ more arguments than locals, the extras are silently dropped. */
+ modeaddr = frameptr + 8;
+ opaddr = localsbase;
+ ix = 0;
+ while (ix < argc) {
+ loctype = Stk1(modeaddr);
+ modeaddr++;
+ locnum = Stk1(modeaddr);
+ modeaddr++;
+ if (loctype == 0)
+ break;
+ if (loctype == 4) {
+ while (opaddr & 3)
+ opaddr++;
+ while (ix < argc && locnum) {
+ val = argv[ix];
+ StkW4(opaddr, val);
+ opaddr += 4;
+ ix++;
+ locnum--;
+ }
+ } else if (loctype == 2) {
+ while (opaddr & 1)
+ opaddr++;
+ while (ix < argc && locnum) {
+ val = argv[ix] & 0xFFFF;
+ StkW2(opaddr, val);
+ opaddr += 2;
+ ix++;
+ locnum--;
+ }
+ } else if (loctype == 1) {
+ while (ix < argc && locnum) {
+ val = argv[ix] & 0xFF;
+ StkW1(opaddr, val);
+ opaddr += 1;
+ ix++;
+ locnum--;
+ }
+ }
+ }
+ }
+
+ /* If the debugger is compiled in, check for a breakpoint on this
+ function. (Checking the function address, not the starting PC.) */
+ debugger_check_func_breakpoint(funcaddr);
}
void Glulxe::leave_function() {
- profile_out(stackptr);
- stackptr = frameptr;
+ profile_out(stackptr);
+ stackptr = frameptr;
}
void Glulxe::push_callstub(uint desttype, uint destaddr) {
- if (stackptr+16 > stacksize)
- fatal_error("Stack overflow in callstub.");
- StkW4(stackptr+0, desttype);
- StkW4(stackptr+4, destaddr);
- StkW4(stackptr+8, pc);
- StkW4(stackptr+12, frameptr);
- stackptr += 16;
+ if (stackptr + 16 > stacksize)
+ fatal_error("Stack overflow in callstub.");
+ StkW4(stackptr + 0, desttype);
+ StkW4(stackptr + 4, destaddr);
+ StkW4(stackptr + 8, pc);
+ StkW4(stackptr + 12, frameptr);
+ stackptr += 16;
}
void Glulxe::pop_callstub(uint returnvalue) {
- uint desttype, destaddr;
- uint newpc, newframeptr;
-
- if (stackptr < 16)
- fatal_error("Stack underflow in callstub.");
- stackptr -= 16;
-
- newframeptr = Stk4(stackptr+12);
- newpc = Stk4(stackptr+8);
- destaddr = Stk4(stackptr+4);
- desttype = Stk4(stackptr+0);
-
- pc = newpc;
- frameptr = newframeptr;
-
- /* Recompute valstackbase and localsbase */
- valstackbase = frameptr + Stk4(frameptr);
- localsbase = frameptr + Stk4(frameptr+4);
-
- switch (desttype) {
-
- case 0x11:
- fatal_error("String-terminator call stub at end of function call.");
- break;
-
- case 0x10:
- /* This call stub was pushed during a string-decoding operation!
- We have to restart it. (Note that the return value is discarded.) */
- stream_string(pc, 0xE1, destaddr);
- break;
-
- case 0x12:
- /* This call stub was pushed during a number-printing operation.
- Restart that. (Return value discarded.) */
- stream_num(pc, true, destaddr);
- break;
-
- case 0x13:
- /* This call stub was pushed during a C-string printing operation.
- We have to restart it. (Note that the return value is discarded.) */
- stream_string(pc, 0xE0, destaddr);
- break;
-
- case 0x14:
- /* This call stub was pushed during a Unicode printing operation.
- We have to restart it. (Note that the return value is discarded.) */
- stream_string(pc, 0xE2, destaddr);
- break;
-
- default:
- /* We're back in the original frame, so we can store the returnvalue.
- (If we tried to do this before resetting frameptr, a result
- destination on the stack would go astray.) */
- store_operand(desttype, destaddr, returnvalue);
- break;
- }
+ uint desttype, destaddr;
+ uint newpc, newframeptr;
+
+ if (stackptr < 16)
+ fatal_error("Stack underflow in callstub.");
+ stackptr -= 16;
+
+ newframeptr = Stk4(stackptr + 12);
+ newpc = Stk4(stackptr + 8);
+ destaddr = Stk4(stackptr + 4);
+ desttype = Stk4(stackptr + 0);
+
+ pc = newpc;
+ frameptr = newframeptr;
+
+ /* Recompute valstackbase and localsbase */
+ valstackbase = frameptr + Stk4(frameptr);
+ localsbase = frameptr + Stk4(frameptr + 4);
+
+ switch (desttype) {
+
+ case 0x11:
+ fatal_error("String-terminator call stub at end of function call.");
+ break;
+
+ case 0x10:
+ /* This call stub was pushed during a string-decoding operation!
+ We have to restart it. (Note that the return value is discarded.) */
+ stream_string(pc, 0xE1, destaddr);
+ break;
+
+ case 0x12:
+ /* This call stub was pushed during a number-printing operation.
+ Restart that. (Return value discarded.) */
+ stream_num(pc, true, destaddr);
+ break;
+
+ case 0x13:
+ /* This call stub was pushed during a C-string printing operation.
+ We have to restart it. (Note that the return value is discarded.) */
+ stream_string(pc, 0xE0, destaddr);
+ break;
+
+ case 0x14:
+ /* This call stub was pushed during a Unicode printing operation.
+ We have to restart it. (Note that the return value is discarded.) */
+ stream_string(pc, 0xE2, destaddr);
+ break;
+
+ default:
+ /* We're back in the original frame, so we can store the returnvalue.
+ (If we tried to do this before resetting frameptr, a result
+ destination on the stack would go astray.) */
+ store_operand(desttype, destaddr, returnvalue);
+ break;
+ }
}
uint Glulxe::pop_callstub_string(int *bitnum) {
- uint desttype, destaddr, newpc;
+ uint desttype, destaddr, newpc;
- if (stackptr < 16)
- fatal_error("Stack underflow in callstub.");
- stackptr -= 16;
+ if (stackptr < 16)
+ fatal_error("Stack underflow in callstub.");
+ stackptr -= 16;
- newpc = Stk4(stackptr+8);
- destaddr = Stk4(stackptr+4);
- desttype = Stk4(stackptr+0);
+ newpc = Stk4(stackptr + 8);
+ destaddr = Stk4(stackptr + 4);
+ desttype = Stk4(stackptr + 0);
- pc = newpc;
+ pc = newpc;
- if (desttype == 0x11) {
- return 0;
- }
- if (desttype == 0x10) {
- *bitnum = destaddr;
- return pc;
- }
+ if (desttype == 0x11) {
+ return 0;
+ }
+ if (desttype == 0x10) {
+ *bitnum = destaddr;
+ return pc;
+ }
- fatal_error("Function-terminator call stub at end of string.");
- return 0;
+ fatal_error("Function-terminator call stub at end of string.");
+ return 0;
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/gestalt.cpp b/engines/glk/glulxe/gestalt.cpp
index 21f8974513..18f9083b34 100644
--- a/engines/glk/glulxe/gestalt.cpp
+++ b/engines/glk/glulxe/gestalt.cpp
@@ -26,75 +26,75 @@ namespace Glk {
namespace Glulxe {
uint Glulxe::do_gestalt(uint val, uint val2) {
- switch (val) {
+ switch (val) {
- case gestulx_GlulxVersion:
- return 0x00030102; /* Glulx spec version 3.1.2 */
+ case gestulx_GlulxVersion:
+ return 0x00030102; /* Glulx spec version 3.1.2 */
- case gestulx_TerpVersion:
- return 0x00000504; /* Glulxe version 0.5.4 */
+ case gestulx_TerpVersion:
+ return 0x00000504; /* Glulxe version 0.5.4 */
- case gestulx_ResizeMem:
+ case gestulx_ResizeMem:
#ifdef FIXED_MEMSIZE
- return 0; /* The setmemsize opcodes are compiled out. */
+ return 0; /* The setmemsize opcodes are compiled out. */
#else /* FIXED_MEMSIZE */
- return 1; /* We can handle setmemsize. */
+ return 1; /* We can handle setmemsize. */
#endif /* FIXED_MEMSIZE */
- case gestulx_Undo:
- return 1; /* We can handle saveundo and restoreundo. */
+ case gestulx_Undo:
+ return 1; /* We can handle saveundo and restoreundo. */
- case gestulx_IOSystem:
- switch (val2) {
- case 0:
- return 1; /* The "null" system always works. */
- case 1:
- return 1; /* The "filter" system always works. */
- case 2:
- return 1; /* A Glk library is hooked up. */
- default:
- return 0;
- }
+ case gestulx_IOSystem:
+ switch (val2) {
+ case 0:
+ return 1; /* The "null" system always works. */
+ case 1:
+ return 1; /* The "filter" system always works. */
+ case 2:
+ return 1; /* A Glk library is hooked up. */
+ default:
+ return 0;
+ }
- case gestulx_Unicode:
- return 1; /* We can handle Unicode. */
+ case gestulx_Unicode:
+ return 1; /* We can handle Unicode. */
- case gestulx_MemCopy:
- return 1; /* We can do mcopy/mzero. */
+ case gestulx_MemCopy:
+ return 1; /* We can do mcopy/mzero. */
- case gestulx_MAlloc:
+ case gestulx_MAlloc:
#ifdef FIXED_MEMSIZE
- return 0; /* The malloc opcodes are compiled out. */
+ return 0; /* The malloc opcodes are compiled out. */
#else /* FIXED_MEMSIZE */
- return 1; /* We can handle malloc/mfree. */
+ return 1; /* We can handle malloc/mfree. */
#endif /* FIXED_MEMSIZE */
- case gestulx_MAllocHeap:
- return heap_get_start();
+ case gestulx_MAllocHeap:
+ return heap_get_start();
- case gestulx_Acceleration:
- return 1; /* We can do accelfunc/accelparam. */
+ case gestulx_Acceleration:
+ return 1; /* We can do accelfunc/accelparam. */
- case gestulx_AccelFunc:
- if (accel_find_func(val2))
- return 1; /* We know this accelerated function. */
- return 0;
+ case gestulx_AccelFunc:
+ if (accel_find_func(val2))
+ return 1; /* We know this accelerated function. */
+ return 0;
- case gestulx_Float:
+ case gestulx_Float:
#ifdef FLOAT_SUPPORT
- return 1; /* We can do floating-point operations. */
+ return 1; /* We can do floating-point operations. */
#else /* FLOAT_SUPPORT */
- return 0; /* The floating-point opcodes are not compiled in. */
+ return 0; /* The floating-point opcodes are not compiled in. */
#endif /* FLOAT_SUPPORT */
#ifdef GLULX_EXTEND_GESTALT
- GLULX_EXTEND_GESTALT
+ GLULX_EXTEND_GESTALT
#endif /* GLULX_EXTEND_GESTALT */
- default:
- return 0;
+ default:
+ return 0;
- }
+ }
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/glkop.cpp b/engines/glk/glulxe/glkop.cpp
index 12d4fef0d3..cb912ecb19 100644
--- a/engines/glk/glulxe/glkop.cpp
+++ b/engines/glk/glulxe/glkop.cpp
@@ -27,7 +27,7 @@ namespace Glulxe {
/* This code is actually very general; it could work for almost any
32-bit VM which remotely resembles Glulxe or the Z-machine in design.
-
+
To be precise, we make the following assumptions:
- An argument list is an array of 32-bit values, which can represent
@@ -66,41 +66,41 @@ namespace Glulxe {
*/
#define ReadMemory(addr) \
- (((addr) == 0xffffffff) \
- ? (stackptr -= 4, Stk4(stackptr)) \
- : (Mem4(addr)))
+ (((addr) == 0xffffffff) \
+ ? (stackptr -= 4, Stk4(stackptr)) \
+ : (Mem4(addr)))
#define WriteMemory(addr, val) \
- (((addr) == 0xffffffff) \
- ? (StkW4(stackptr, (val)), stackptr += 4) \
- : (MemW4((addr), (val))))
+ (((addr) == 0xffffffff) \
+ ? (StkW4(stackptr, (val)), stackptr += 4) \
+ : (MemW4((addr), (val))))
#define CaptureCArray(addr, len, passin) \
- (grab_temp_c_array(addr, len, passin))
+ (grab_temp_c_array(addr, len, passin))
#define ReleaseCArray(ptr, addr, len, passout) \
- (release_temp_c_array(ptr, addr, len, passout))
+ (release_temp_c_array(ptr, addr, len, passout))
#define CaptureIArray(addr, len, passin) \
- (grab_temp_i_array(addr, len, passin))
+ (grab_temp_i_array(addr, len, passin))
#define ReleaseIArray(ptr, addr, len, passout) \
- (release_temp_i_array(ptr, addr, len, passout))
+ (release_temp_i_array(ptr, addr, len, passout))
#define CapturePtrArray(addr, len, objclass, passin) \
- (grab_temp_ptr_array(addr, len, objclass, passin))
+ (grab_temp_ptr_array(addr, len, objclass, passin))
#define ReleasePtrArray(ptr, addr, len, objclass, passout) \
- (release_temp_ptr_array(ptr, addr, len, objclass, passout))
+ (release_temp_ptr_array(ptr, addr, len, objclass, passout))
#define ReadStructField(addr, fieldnum) \
- (((addr) == 0xffffffff) \
- ? (stackptr -= 4, Stk4(stackptr)) \
- : (Mem4((addr)+(fieldnum)*4)))
+ (((addr) == 0xffffffff) \
+ ? (stackptr -= 4, Stk4(stackptr)) \
+ : (Mem4((addr)+(fieldnum)*4)))
#define WriteStructField(addr, fieldnum, val) \
- (((addr) == 0xffffffff) \
- ? (StkW4(stackptr, (val)), stackptr += 4) \
- : (MemW4((addr)+(fieldnum)*4, (val))))
+ (((addr) == 0xffffffff) \
+ ? (StkW4(stackptr, (val)), stackptr += 4) \
+ : (MemW4((addr)+(fieldnum)*4, (val))))
#define DecodeVMString(addr) \
- (make_temp_string(addr))
+ (make_temp_string(addr))
#define ReleaseVMString(ptr) \
- (free_temp_string(ptr))
+ (free_temp_string(ptr))
#define DecodeVMUstring(addr) \
- (make_temp_ustring(addr))
+ (make_temp_ustring(addr))
#define ReleaseVMUstring(ptr) \
- (free_temp_ustring(ptr))
+ (free_temp_ustring(ptr))
static gidispatch_rock_t classtable_register(void *obj, uint objclass) {
return g_vm->glulxe_classtable_register(obj, objclass);
@@ -129,1252 +129,1213 @@ void Glulxe::glkopInit() {
Set up the class hash tables and other startup-time stuff.
*/
bool Glulxe::init_dispatch() {
- int ix;
-
- /* What with one thing and another, this *could* be called more than
- once. We only need to allocate the tables once. */
- if (classes)
- return true;
-
- /* Set up the game-ID hook. (This is ifdeffed because not all Glk
- libraries have this call.) */
+ int ix;
+
+ /* What with one thing and another, this *could* be called more than
+ once. We only need to allocate the tables once. */
+ if (classes)
+ return true;
+
+ /* Set up the game-ID hook. (This is ifdeffed because not all Glk
+ libraries have this call.) */
#ifdef GI_DISPA_GAME_ID_AVAILABLE
- gidispatch_set_game_id_hook(&get_game_id);
+ gidispatch_set_game_id_hook(&get_game_id);
#endif /* GI_DISPA_GAME_ID_AVAILABLE */
-
- /* Allocate the class hash tables. */
- num_classes = gidispatch_count_classes();
- classes = (classtable_t **)glulx_malloc(num_classes * sizeof(classtable_t *));
- if (!classes)
- return false;
-
- for (ix=0; ix<num_classes; ix++) {
- classes[ix] = new_classtable((glulx_random() % (uint)(101)) + 1);
- if (!classes[ix])
- return false;
- }
-
- /* Set up the two callbacks. */
- gidispatch_set_object_registry(&classtable_register, &classtable_unregister);
- gidispatch_set_retained_registry(&retained_register, &retained_unregister);
-
- /* If the library supports autorestore callbacks, set those up too.
- (These are only used in iosglk, currently.) */
+
+ /* Allocate the class hash tables. */
+ num_classes = gidispatch_count_classes();
+ classes = (classtable_t **)glulx_malloc(num_classes * sizeof(classtable_t *));
+ if (!classes)
+ return false;
+
+ for (ix = 0; ix < num_classes; ix++) {
+ classes[ix] = new_classtable((glulx_random() % (uint)(101)) + 1);
+ if (!classes[ix])
+ return false;
+ }
+
+ /* Set up the two callbacks. */
+ gidispatch_set_object_registry(&classtable_register, &classtable_unregister);
+ gidispatch_set_retained_registry(&retained_register, &retained_unregister);
+
+ /* If the library supports autorestore callbacks, set those up too.
+ (These are only used in iosglk, currently.) */
#ifdef GIDISPATCH_AUTORESTORE_REGISTRY
- gidispatch_set_autorestore_registry(&glulxe_array_locate, &glulxe_array_restore);
+ gidispatch_set_autorestore_registry(&glulxe_array_locate, &glulxe_array_restore);
#endif /* GIDISPATCH_AUTORESTORE_REGISTRY */
-
- return true;
+
+ return true;
}
uint Glulxe::perform_glk(uint funcnum, uint numargs, uint *arglist) {
- uint retval = 0;
-
- switch (funcnum) {
- /* To speed life up, we implement commonly-used Glk functions
- directly -- instead of bothering with the whole prototype
- mess. */
-
- case 0x0047: /* stream_set_current */
- if (numargs != 1)
- goto WrongArgNum;
- glk_stream_set_current(find_stream_by_id(arglist[0]));
- break;
- case 0x0048: /* stream_get_current */
- if (numargs != 0)
- goto WrongArgNum;
- retval = find_id_for_stream(glk_stream_get_current());
- break;
- case 0x0080: /* put_char */
- if (numargs != 1)
- goto WrongArgNum;
- glk_put_char(arglist[0] & 0xFF);
- break;
- case 0x0081: /* put_char_stream */
- if (numargs != 2)
- goto WrongArgNum;
- glk_put_char_stream(find_stream_by_id(arglist[0]), arglist[1] & 0xFF);
- break;
- case 0x00C0: /* select */
- /* call a library hook on every glk_select() */
- if (library_select_hook)
- library_select_hook(arglist[0]);
- /* but then fall through to full dispatcher, because there's no real
- need for speed here */
- goto FullDispatcher;
- case 0x00A0: /* char_to_lower */
- if (numargs != 1)
- goto WrongArgNum;
- retval = glk_char_to_lower(arglist[0] & 0xFF);
- break;
- case 0x00A1: /* char_to_upper */
- if (numargs != 1)
- goto WrongArgNum;
- retval = glk_char_to_upper(arglist[0] & 0xFF);
- break;
- case 0x0128: /* put_char_uni */
- if (numargs != 1)
- goto WrongArgNum;
- glk_put_char_uni(arglist[0]);
- break;
- case 0x012B: /* put_char_stream_uni */
- if (numargs != 2)
- goto WrongArgNum;
- glk_put_char_stream_uni(find_stream_by_id(arglist[0]), arglist[1]);
- break;
-
- WrongArgNum:
- error("Wrong number of arguments to Glk function.");
- break;
-
- FullDispatcher:
- default: {
- /* Go through the full dispatcher prototype foo. */
- const char *proto, *cx;
- dispatch_splot_t splot;
- int argnum, argnum2;
-
- /* Grab the string. */
- proto = gidispatch_prototype(funcnum);
- if (!proto)
- error("Unknown Glk function.");
-
- splot.varglist = arglist;
- splot.numvargs = numargs;
- splot.retval = &retval;
-
- /* The work goes in four phases. First, we figure out how many
- arguments we want, and allocate space for the Glk argument
- list. Then we go through the Glulxe arguments and load them
- into the Glk list. Then we call. Then we go through the
- arguments again, unloading the data back into Glulx memory. */
-
- /* Phase 0. */
- prepare_glk_args(proto, &splot);
-
- /* Phase 1. */
- argnum = 0;
- cx = proto;
- parse_glk_args(&splot, &cx, 0, &argnum, 0, 0);
-
- /* Phase 2. */
- gidispatch_call(funcnum, argnum, splot.garglist);
-
- /* Phase 3. */
- argnum2 = 0;
- cx = proto;
- unparse_glk_args(&splot, &cx, 0, &argnum2, 0, 0);
- if (argnum != argnum2)
- error("Argument counts did not match.");
-
- break;
- }
- }
-
- return retval;
+ uint retval = 0;
+
+ switch (funcnum) {
+ /* To speed life up, we implement commonly-used Glk functions
+ directly -- instead of bothering with the whole prototype
+ mess. */
+
+ case 0x0047: /* stream_set_current */
+ if (numargs != 1)
+ goto WrongArgNum;
+ glk_stream_set_current(find_stream_by_id(arglist[0]));
+ break;
+ case 0x0048: /* stream_get_current */
+ if (numargs != 0)
+ goto WrongArgNum;
+ retval = find_id_for_stream(glk_stream_get_current());
+ break;
+ case 0x0080: /* put_char */
+ if (numargs != 1)
+ goto WrongArgNum;
+ glk_put_char(arglist[0] & 0xFF);
+ break;
+ case 0x0081: /* put_char_stream */
+ if (numargs != 2)
+ goto WrongArgNum;
+ glk_put_char_stream(find_stream_by_id(arglist[0]), arglist[1] & 0xFF);
+ break;
+ case 0x00C0: /* select */
+ /* call a library hook on every glk_select() */
+ if (library_select_hook)
+ library_select_hook(arglist[0]);
+ /* but then fall through to full dispatcher, because there's no real
+ need for speed here */
+ goto FullDispatcher;
+ case 0x00A0: /* char_to_lower */
+ if (numargs != 1)
+ goto WrongArgNum;
+ retval = glk_char_to_lower(arglist[0] & 0xFF);
+ break;
+ case 0x00A1: /* char_to_upper */
+ if (numargs != 1)
+ goto WrongArgNum;
+ retval = glk_char_to_upper(arglist[0] & 0xFF);
+ break;
+ case 0x0128: /* put_char_uni */
+ if (numargs != 1)
+ goto WrongArgNum;
+ glk_put_char_uni(arglist[0]);
+ break;
+ case 0x012B: /* put_char_stream_uni */
+ if (numargs != 2)
+ goto WrongArgNum;
+ glk_put_char_stream_uni(find_stream_by_id(arglist[0]), arglist[1]);
+ break;
+
+WrongArgNum:
+ error("Wrong number of arguments to Glk function.");
+ break;
+
+FullDispatcher:
+ default: {
+ /* Go through the full dispatcher prototype foo. */
+ const char *proto, *cx;
+ dispatch_splot_t splot;
+ int argnum, argnum2;
+
+ /* Grab the string. */
+ proto = gidispatch_prototype(funcnum);
+ if (!proto)
+ error("Unknown Glk function.");
+
+ splot.varglist = arglist;
+ splot.numvargs = numargs;
+ splot.retval = &retval;
+
+ /* The work goes in four phases. First, we figure out how many
+ arguments we want, and allocate space for the Glk argument
+ list. Then we go through the Glulxe arguments and load them
+ into the Glk list. Then we call. Then we go through the
+ arguments again, unloading the data back into Glulx memory. */
+
+ /* Phase 0. */
+ prepare_glk_args(proto, &splot);
+
+ /* Phase 1. */
+ argnum = 0;
+ cx = proto;
+ parse_glk_args(&splot, &cx, 0, &argnum, 0, 0);
+
+ /* Phase 2. */
+ gidispatch_call(funcnum, argnum, splot.garglist);
+
+ /* Phase 3. */
+ argnum2 = 0;
+ cx = proto;
+ unparse_glk_args(&splot, &cx, 0, &argnum2, 0, 0);
+ if (argnum != argnum2)
+ error("Argument counts did not match.");
+
+ break;
+ }
+ }
+
+ return retval;
}
const char *Glulxe::read_prefix(const char *cx, int *isref, int *isarray, int *passin, int *passout,
- int *nullok, int *isretained, int *isreturn) {
- *isref = false;
- *passin = false;
- *passout = false;
- *nullok = true;
- *isarray = false;
- *isretained = false;
- *isreturn = false;
- while (1) {
- if (*cx == '<') {
- *isref = true;
- *passout = true;
- }
- else if (*cx == '>') {
- *isref = true;
- *passin = true;
- }
- else if (*cx == '&') {
- *isref = true;
- *passout = true;
- *passin = true;
- }
- else if (*cx == '+') {
- *nullok = false;
- }
- else if (*cx == ':') {
- *isref = true;
- *passout = true;
- *nullok = false;
- *isreturn = true;
- }
- else if (*cx == '#') {
- *isarray = true;
- }
- else if (*cx == '!') {
- *isretained = true;
- }
- else {
- break;
- }
- cx++;
- }
- return cx;
+ int *nullok, int *isretained, int *isreturn) {
+ *isref = false;
+ *passin = false;
+ *passout = false;
+ *nullok = true;
+ *isarray = false;
+ *isretained = false;
+ *isreturn = false;
+ while (1) {
+ if (*cx == '<') {
+ *isref = true;
+ *passout = true;
+ } else if (*cx == '>') {
+ *isref = true;
+ *passin = true;
+ } else if (*cx == '&') {
+ *isref = true;
+ *passout = true;
+ *passin = true;
+ } else if (*cx == '+') {
+ *nullok = false;
+ } else if (*cx == ':') {
+ *isref = true;
+ *passout = true;
+ *nullok = false;
+ *isreturn = true;
+ } else if (*cx == '#') {
+ *isarray = true;
+ } else if (*cx == '!') {
+ *isretained = true;
+ } else {
+ break;
+ }
+ cx++;
+ }
+ return cx;
}
void Glulxe::prepare_glk_args(const char *proto, dispatch_splot_t *splot) {
- static gluniversal_t *garglist = nullptr;
- static int garglist_size = 0;
-
- int ix;
- int numwanted, numvargswanted, maxargs;
- const char *cx;
-
- cx = proto;
- numwanted = 0;
- while (*cx >= '0' && *cx <= '9') {
- numwanted = 10 * numwanted + (*cx - '0');
- cx++;
- }
- splot->numwanted = numwanted;
-
- maxargs = 0;
- numvargswanted = 0;
- for (ix = 0; ix < numwanted; ix++) {
- int isref, passin, passout, nullok, isarray, isretained, isreturn;
- cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok,
- &isretained, &isreturn);
- if (isref) {
- maxargs += 2;
- }
- else {
- maxargs += 1;
- }
- if (!isreturn) {
- if (isarray) {
- numvargswanted += 2;
- }
- else {
- numvargswanted += 1;
- }
- }
-
- if (*cx == 'I' || *cx == 'C') {
- cx += 2;
- }
- else if (*cx == 'Q') {
- cx += 2;
- }
- else if (*cx == 'S' || *cx == 'U') {
- cx += 1;
- }
- else if (*cx == '[') {
- int refdepth, nwx;
- cx++;
- nwx = 0;
- while (*cx >= '0' && *cx <= '9') {
- nwx = 10 * nwx + (*cx - '0');
- cx++;
- }
- maxargs += nwx; /* This is *only* correct because all structs contain
+ static gluniversal_t *garglist = nullptr;
+ static int garglist_size = 0;
+
+ int ix;
+ int numwanted, numvargswanted, maxargs;
+ const char *cx;
+
+ cx = proto;
+ numwanted = 0;
+ while (*cx >= '0' && *cx <= '9') {
+ numwanted = 10 * numwanted + (*cx - '0');
+ cx++;
+ }
+ splot->numwanted = numwanted;
+
+ maxargs = 0;
+ numvargswanted = 0;
+ for (ix = 0; ix < numwanted; ix++) {
+ int isref, passin, passout, nullok, isarray, isretained, isreturn;
+ cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok,
+ &isretained, &isreturn);
+ if (isref) {
+ maxargs += 2;
+ } else {
+ maxargs += 1;
+ }
+ if (!isreturn) {
+ if (isarray) {
+ numvargswanted += 2;
+ } else {
+ numvargswanted += 1;
+ }
+ }
+
+ if (*cx == 'I' || *cx == 'C') {
+ cx += 2;
+ } else if (*cx == 'Q') {
+ cx += 2;
+ } else if (*cx == 'S' || *cx == 'U') {
+ cx += 1;
+ } else if (*cx == '[') {
+ int refdepth, nwx;
+ cx++;
+ nwx = 0;
+ while (*cx >= '0' && *cx <= '9') {
+ nwx = 10 * nwx + (*cx - '0');
+ cx++;
+ }
+ maxargs += nwx; /* This is *only* correct because all structs contain
plain values. */
- refdepth = 1;
- while (refdepth > 0) {
- if (*cx == '[')
- refdepth++;
- else if (*cx == ']')
- refdepth--;
- cx++;
- }
- }
- else {
- error("Illegal format string.");
- }
- }
-
- if (*cx != ':' && *cx != '\0')
- error("Illegal format string.");
-
- splot->maxargs = maxargs;
-
- if (splot->numvargs != numvargswanted)
- error("Wrong number of arguments to Glk function.");
-
- if (garglist && garglist_size < maxargs) {
- glulx_free(garglist);
- garglist = nullptr;
- garglist_size = 0;
- }
- if (!garglist) {
- garglist_size = maxargs + 16;
- garglist = (gluniversal_t *)glulx_malloc(garglist_size
- * sizeof(gluniversal_t));
- }
- if (!garglist)
- error("Unable to allocate storage for Glk arguments.");
-
- splot->garglist = garglist;
+ refdepth = 1;
+ while (refdepth > 0) {
+ if (*cx == '[')
+ refdepth++;
+ else if (*cx == ']')
+ refdepth--;
+ cx++;
+ }
+ } else {
+ error("Illegal format string.");
+ }
+ }
+
+ if (*cx != ':' && *cx != '\0')
+ error("Illegal format string.");
+
+ splot->maxargs = maxargs;
+
+ if (splot->numvargs != numvargswanted)
+ error("Wrong number of arguments to Glk function.");
+
+ if (garglist && garglist_size < maxargs) {
+ glulx_free(garglist);
+ garglist = nullptr;
+ garglist_size = 0;
+ }
+ if (!garglist) {
+ garglist_size = maxargs + 16;
+ garglist = (gluniversal_t *)glulx_malloc(garglist_size
+ * sizeof(gluniversal_t));
+ }
+ if (!garglist)
+ error("Unable to allocate storage for Glk arguments.");
+
+ splot->garglist = garglist;
}
void Glulxe::parse_glk_args(dispatch_splot_t *splot, const char **proto, int depth, int *argnumptr,
- uint subaddress, int subpassin) {
- const char *cx;
- int ix, argx;
- int gargnum, numwanted;
- void *opref;
- gluniversal_t *garglist;
- uint *varglist;
-
- garglist = splot->garglist;
- varglist = splot->varglist;
- gargnum = *argnumptr;
- cx = *proto;
-
- numwanted = 0;
- while (*cx >= '0' && *cx <= '9') {
- numwanted = 10 * numwanted + (*cx - '0');
- cx++;
- }
-
- for (argx = 0, ix = 0; argx < numwanted; argx++, ix++) {
- char typeclass;
- int skipval;
- int isref, passin, passout, nullok, isarray, isretained, isreturn;
- cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok,
- &isretained, &isreturn);
-
- typeclass = *cx;
- cx++;
-
- skipval = false;
- if (isref) {
- if (!isreturn && varglist[ix] == 0) {
- if (!nullok)
- error("Zero passed invalidly to Glk function.");
- garglist[gargnum]._ptrflag = false;
- gargnum++;
- skipval = true;
- }
- else {
- garglist[gargnum]._ptrflag = true;
- gargnum++;
- }
- }
- if (!skipval) {
- uint thisval;
-
- if (typeclass == '[') {
-
- parse_glk_args(splot, &cx, depth+1, &gargnum, varglist[ix], passin);
-
- }
- else if (isarray) {
- /* definitely isref */
-
- switch (typeclass) {
- case 'C':
- /* This test checks for a giant array length, which is
- deprecated. It displays a warning and cuts it down to
- something reasonable. Future releases of this interpreter
- may remove this test and go on to verify_array_addresses(),
- which treats this case as a fatal error. */
- if (varglist[ix+1] > endmem
- || varglist[ix]+varglist[ix+1] > endmem) {
- nonfatal_warning_i("Memory access was much too long -- perhaps a print_to_array call with only one argument", varglist[ix+1]);
- varglist[ix+1] = endmem - varglist[ix];
- }
- verify_array_addresses(varglist[ix], varglist[ix+1], 1);
- garglist[gargnum]._array = CaptureCArray(varglist[ix], varglist[ix+1], passin);
- gargnum++;
- ix++;
- garglist[gargnum]._uint = varglist[ix];
- gargnum++;
- cx++;
- break;
- case 'I':
- /* See comment above. */
- if (varglist[ix+1] > endmem/4
- || varglist[ix+1] > (endmem-varglist[ix])/4) {
- nonfatal_warning_i("Memory access was much too long -- perhaps a print_to_array call with only one argument", varglist[ix+1]);
- varglist[ix+1] = (endmem - varglist[ix]) / 4;
- }
- verify_array_addresses(varglist[ix], varglist[ix+1], 4);
- garglist[gargnum]._array = CaptureIArray(varglist[ix], varglist[ix+1], passin);
- gargnum++;
- ix++;
- garglist[gargnum]._uint = varglist[ix];
- gargnum++;
- cx++;
- break;
- case 'Q':
- /* This case was added after the giant arrays were deprecated,
- so we don't bother to allow for that case. We just verify
- the length. */
- verify_array_addresses(varglist[ix], varglist[ix+1], 4);
- garglist[gargnum]._array = CapturePtrArray(varglist[ix], varglist[ix+1], (*cx-'a'), passin);
- gargnum++;
- ix++;
- garglist[gargnum]._uint = varglist[ix];
- gargnum++;
- cx++;
- break;
- default:
- error("Illegal format string.");
- break;
- }
- }
- else {
- /* a plain value or a reference to one. */
-
- if (isreturn) {
- thisval = 0;
- }
- else if (depth > 0) {
- /* Definitely not isref or isarray. */
- if (subpassin)
- thisval = ReadStructField(subaddress, ix);
- else
- thisval = 0;
- }
- else if (isref) {
- if (passin)
- thisval = ReadMemory(varglist[ix]);
- else
- thisval = 0;
- }
- else {
- thisval = varglist[ix];
- }
-
- switch (typeclass) {
- case 'I':
- if (*cx == 'u')
- garglist[gargnum]._uint = (uint)(thisval);
- else if (*cx == 's')
- garglist[gargnum]._sint = (int)(thisval);
- else
- error("Illegal format string.");
- gargnum++;
- cx++;
- break;
- case 'Q':
- if (thisval) {
- opref = classes_get(*cx-'a', thisval);
- if (!opref) {
- error("Reference to nonexistent Glk object.");
- }
- }
- else {
- opref = nullptr;
- }
- garglist[gargnum]._opaqueref = opref;
- gargnum++;
- cx++;
- break;
- case 'C':
- if (*cx == 'u')
- garglist[gargnum]._uch = (unsigned char)(thisval);
- else if (*cx == 's')
- garglist[gargnum]._sch = (signed char)(thisval);
- else if (*cx == 'n')
- garglist[gargnum]._ch = (char)(thisval);
- else
- error("Illegal format string.");
- gargnum++;
- cx++;
- break;
- case 'S':
- garglist[gargnum]._charstr = DecodeVMString(thisval);
- gargnum++;
- break;
+ uint subaddress, int subpassin) {
+ const char *cx;
+ int ix, argx;
+ int gargnum, numwanted;
+ void *opref;
+ gluniversal_t *garglist;
+ uint *varglist;
+
+ garglist = splot->garglist;
+ varglist = splot->varglist;
+ gargnum = *argnumptr;
+ cx = *proto;
+
+ numwanted = 0;
+ while (*cx >= '0' && *cx <= '9') {
+ numwanted = 10 * numwanted + (*cx - '0');
+ cx++;
+ }
+
+ for (argx = 0, ix = 0; argx < numwanted; argx++, ix++) {
+ char typeclass;
+ int skipval;
+ int isref, passin, passout, nullok, isarray, isretained, isreturn;
+ cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok,
+ &isretained, &isreturn);
+
+ typeclass = *cx;
+ cx++;
+
+ skipval = false;
+ if (isref) {
+ if (!isreturn && varglist[ix] == 0) {
+ if (!nullok)
+ error("Zero passed invalidly to Glk function.");
+ garglist[gargnum]._ptrflag = false;
+ gargnum++;
+ skipval = true;
+ } else {
+ garglist[gargnum]._ptrflag = true;
+ gargnum++;
+ }
+ }
+ if (!skipval) {
+ uint thisval;
+
+ if (typeclass == '[') {
+
+ parse_glk_args(splot, &cx, depth + 1, &gargnum, varglist[ix], passin);
+
+ } else if (isarray) {
+ /* definitely isref */
+
+ switch (typeclass) {
+ case 'C':
+ /* This test checks for a giant array length, which is
+ deprecated. It displays a warning and cuts it down to
+ something reasonable. Future releases of this interpreter
+ may remove this test and go on to verify_array_addresses(),
+ which treats this case as a fatal error. */
+ if (varglist[ix + 1] > endmem
+ || varglist[ix] + varglist[ix + 1] > endmem) {
+ nonfatal_warning_i("Memory access was much too long -- perhaps a print_to_array call with only one argument", varglist[ix + 1]);
+ varglist[ix + 1] = endmem - varglist[ix];
+ }
+ verify_array_addresses(varglist[ix], varglist[ix + 1], 1);
+ garglist[gargnum]._array = CaptureCArray(varglist[ix], varglist[ix + 1], passin);
+ gargnum++;
+ ix++;
+ garglist[gargnum]._uint = varglist[ix];
+ gargnum++;
+ cx++;
+ break;
+ case 'I':
+ /* See comment above. */
+ if (varglist[ix + 1] > endmem / 4
+ || varglist[ix + 1] > (endmem - varglist[ix]) / 4) {
+ nonfatal_warning_i("Memory access was much too long -- perhaps a print_to_array call with only one argument", varglist[ix + 1]);
+ varglist[ix + 1] = (endmem - varglist[ix]) / 4;
+ }
+ verify_array_addresses(varglist[ix], varglist[ix + 1], 4);
+ garglist[gargnum]._array = CaptureIArray(varglist[ix], varglist[ix + 1], passin);
+ gargnum++;
+ ix++;
+ garglist[gargnum]._uint = varglist[ix];
+ gargnum++;
+ cx++;
+ break;
+ case 'Q':
+ /* This case was added after the giant arrays were deprecated,
+ so we don't bother to allow for that case. We just verify
+ the length. */
+ verify_array_addresses(varglist[ix], varglist[ix + 1], 4);
+ garglist[gargnum]._array = CapturePtrArray(varglist[ix], varglist[ix + 1], (*cx - 'a'), passin);
+ gargnum++;
+ ix++;
+ garglist[gargnum]._uint = varglist[ix];
+ gargnum++;
+ cx++;
+ break;
+ default:
+ error("Illegal format string.");
+ break;
+ }
+ } else {
+ /* a plain value or a reference to one. */
+
+ if (isreturn) {
+ thisval = 0;
+ } else if (depth > 0) {
+ /* Definitely not isref or isarray. */
+ if (subpassin)
+ thisval = ReadStructField(subaddress, ix);
+ else
+ thisval = 0;
+ } else if (isref) {
+ if (passin)
+ thisval = ReadMemory(varglist[ix]);
+ else
+ thisval = 0;
+ } else {
+ thisval = varglist[ix];
+ }
+
+ switch (typeclass) {
+ case 'I':
+ if (*cx == 'u')
+ garglist[gargnum]._uint = (uint)(thisval);
+ else if (*cx == 's')
+ garglist[gargnum]._sint = (int)(thisval);
+ else
+ error("Illegal format string.");
+ gargnum++;
+ cx++;
+ break;
+ case 'Q':
+ if (thisval) {
+ opref = classes_get(*cx - 'a', thisval);
+ if (!opref) {
+ error("Reference to nonexistent Glk object.");
+ }
+ } else {
+ opref = nullptr;
+ }
+ garglist[gargnum]._opaqueref = opref;
+ gargnum++;
+ cx++;
+ break;
+ case 'C':
+ if (*cx == 'u')
+ garglist[gargnum]._uch = (unsigned char)(thisval);
+ else if (*cx == 's')
+ garglist[gargnum]._sch = (signed char)(thisval);
+ else if (*cx == 'n')
+ garglist[gargnum]._ch = (char)(thisval);
+ else
+ error("Illegal format string.");
+ gargnum++;
+ cx++;
+ break;
+ case 'S':
+ garglist[gargnum]._charstr = DecodeVMString(thisval);
+ gargnum++;
+ break;
#ifdef GLK_MODULE_UNICODE
- case 'U':
- garglist[gargnum]._unicharstr = DecodeVMUstring(thisval);
- gargnum++;
- break;
+ case 'U':
+ garglist[gargnum]._unicharstr = DecodeVMUstring(thisval);
+ gargnum++;
+ break;
#endif /* GLK_MODULE_UNICODE */
- default:
- error("Illegal format string.");
- break;
- }
- }
- }
- else {
- /* We got a null reference, so we have to skip the format element. */
- if (typeclass == '[') {
- int numsubwanted, refdepth;
- numsubwanted = 0;
- while (*cx >= '0' && *cx <= '9') {
- numsubwanted = 10 * numsubwanted + (*cx - '0');
- cx++;
- }
- refdepth = 1;
- while (refdepth > 0) {
- if (*cx == '[')
- refdepth++;
- else if (*cx == ']')
- refdepth--;
- cx++;
- }
- }
- else if (typeclass == 'S' || typeclass == 'U') {
- /* leave it */
- }
- else {
- cx++;
- if (isarray)
- ix++;
- }
- }
- }
-
- if (depth > 0) {
- if (*cx != ']')
- error("Illegal format string.");
- cx++;
- }
- else {
- if (*cx != ':' && *cx != '\0')
- error("Illegal format string.");
- }
-
- *proto = cx;
- *argnumptr = gargnum;
+ default:
+ error("Illegal format string.");
+ break;
+ }
+ }
+ } else {
+ /* We got a null reference, so we have to skip the format element. */
+ if (typeclass == '[') {
+ int numsubwanted, refdepth;
+ numsubwanted = 0;
+ while (*cx >= '0' && *cx <= '9') {
+ numsubwanted = 10 * numsubwanted + (*cx - '0');
+ cx++;
+ }
+ refdepth = 1;
+ while (refdepth > 0) {
+ if (*cx == '[')
+ refdepth++;
+ else if (*cx == ']')
+ refdepth--;
+ cx++;
+ }
+ } else if (typeclass == 'S' || typeclass == 'U') {
+ /* leave it */
+ } else {
+ cx++;
+ if (isarray)
+ ix++;
+ }
+ }
+ }
+
+ if (depth > 0) {
+ if (*cx != ']')
+ error("Illegal format string.");
+ cx++;
+ } else {
+ if (*cx != ':' && *cx != '\0')
+ error("Illegal format string.");
+ }
+
+ *proto = cx;
+ *argnumptr = gargnum;
}
void Glulxe::unparse_glk_args(dispatch_splot_t *splot, const char **proto, int depth,
- int *argnumptr, uint subaddress, int subpassout) {
- const char *cx;
- int ix, argx;
- int gargnum, numwanted;
- void *opref;
- gluniversal_t *garglist;
- uint *varglist;
-
- garglist = splot->garglist;
- varglist = splot->varglist;
- gargnum = *argnumptr;
- cx = *proto;
-
- numwanted = 0;
- while (*cx >= '0' && *cx <= '9') {
- numwanted = 10 * numwanted + (*cx - '0');
- cx++;
- }
-
- for (argx = 0, ix = 0; argx < numwanted; argx++, ix++) {
- char typeclass;
- int skipval;
- int isref, passin, passout, nullok, isarray, isretained, isreturn;
- cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok,
- &isretained, &isreturn);
-
- typeclass = *cx;
- cx++;
-
- skipval = false;
- if (isref) {
- if (!isreturn && varglist[ix] == 0) {
- if (!nullok)
- error("Zero passed invalidly to Glk function.");
- garglist[gargnum]._ptrflag = false;
- gargnum++;
- skipval = true;
- } else {
- garglist[gargnum]._ptrflag = true;
- gargnum++;
- }
- }
- if (!skipval) {
- uint thisval = 0;
-
- if (typeclass == '[') {
-
- unparse_glk_args(splot, &cx, depth+1, &gargnum, varglist[ix], passout);
-
- }
- else if (isarray) {
- /* definitely isref */
-
- switch (typeclass) {
- case 'C':
- ReleaseCArray((char *)garglist[gargnum]._array, varglist[ix], varglist[ix+1], passout);
- gargnum++;
- ix++;
- gargnum++;
- cx++;
- break;
- case 'I':
- ReleaseIArray((uint *)garglist[gargnum]._array, varglist[ix], varglist[ix+1], passout);
- gargnum++;
- ix++;
- gargnum++;
- cx++;
- break;
- case 'Q':
- ReleasePtrArray((void **)garglist[gargnum]._array, varglist[ix], varglist[ix+1], (*cx-'a'), passout);
- gargnum++;
- ix++;
- gargnum++;
- cx++;
- break;
- default:
- error("Illegal format string.");
- break;
- }
- }
- else {
- /* a plain value or a reference to one. */
-
- if (isreturn || (depth > 0 && subpassout) || (isref && passout)) {
- skipval = false;
- }
- else {
- skipval = true;
- }
-
- switch (typeclass) {
- case 'I':
- if (!skipval) {
- if (*cx == 'u')
- thisval = (uint)garglist[gargnum]._uint;
- else if (*cx == 's')
- thisval = (uint)garglist[gargnum]._sint;
- else
- error("Illegal format string.");
- }
- gargnum++;
- cx++;
- break;
- case 'Q':
- if (!skipval) {
- opref = garglist[gargnum]._opaqueref;
- if (opref) {
- gidispatch_rock_t objrock = gidispatch_get_objrock(opref, *cx - 'a');
- thisval = ((classref_t *)objrock.ptr)->id;
- }
- else {
- thisval = 0;
- }
- }
- gargnum++;
- cx++;
- break;
- case 'C':
- if (!skipval) {
- if (*cx == 'u')
- thisval = (uint)garglist[gargnum]._uch;
- else if (*cx == 's')
- thisval = (uint)garglist[gargnum]._sch;
- else if (*cx == 'n')
- thisval = (uint)garglist[gargnum]._ch;
- else
- error("Illegal format string.");
- }
- gargnum++;
- cx++;
- break;
- case 'S':
- if (garglist[gargnum]._charstr)
- ReleaseVMString(garglist[gargnum]._charstr);
- gargnum++;
- break;
+ int *argnumptr, uint subaddress, int subpassout) {
+ const char *cx;
+ int ix, argx;
+ int gargnum, numwanted;
+ void *opref;
+ gluniversal_t *garglist;
+ uint *varglist;
+
+ garglist = splot->garglist;
+ varglist = splot->varglist;
+ gargnum = *argnumptr;
+ cx = *proto;
+
+ numwanted = 0;
+ while (*cx >= '0' && *cx <= '9') {
+ numwanted = 10 * numwanted + (*cx - '0');
+ cx++;
+ }
+
+ for (argx = 0, ix = 0; argx < numwanted; argx++, ix++) {
+ char typeclass;
+ int skipval;
+ int isref, passin, passout, nullok, isarray, isretained, isreturn;
+ cx = read_prefix(cx, &isref, &isarray, &passin, &passout, &nullok,
+ &isretained, &isreturn);
+
+ typeclass = *cx;
+ cx++;
+
+ skipval = false;
+ if (isref) {
+ if (!isreturn && varglist[ix] == 0) {
+ if (!nullok)
+ error("Zero passed invalidly to Glk function.");
+ garglist[gargnum]._ptrflag = false;
+ gargnum++;
+ skipval = true;
+ } else {
+ garglist[gargnum]._ptrflag = true;
+ gargnum++;
+ }
+ }
+ if (!skipval) {
+ uint thisval = 0;
+
+ if (typeclass == '[') {
+
+ unparse_glk_args(splot, &cx, depth + 1, &gargnum, varglist[ix], passout);
+
+ } else if (isarray) {
+ /* definitely isref */
+
+ switch (typeclass) {
+ case 'C':
+ ReleaseCArray((char *)garglist[gargnum]._array, varglist[ix], varglist[ix + 1], passout);
+ gargnum++;
+ ix++;
+ gargnum++;
+ cx++;
+ break;
+ case 'I':
+ ReleaseIArray((uint *)garglist[gargnum]._array, varglist[ix], varglist[ix + 1], passout);
+ gargnum++;
+ ix++;
+ gargnum++;
+ cx++;
+ break;
+ case 'Q':
+ ReleasePtrArray((void **)garglist[gargnum]._array, varglist[ix], varglist[ix + 1], (*cx - 'a'), passout);
+ gargnum++;
+ ix++;
+ gargnum++;
+ cx++;
+ break;
+ default:
+ error("Illegal format string.");
+ break;
+ }
+ } else {
+ /* a plain value or a reference to one. */
+
+ if (isreturn || (depth > 0 && subpassout) || (isref && passout)) {
+ skipval = false;
+ } else {
+ skipval = true;
+ }
+
+ switch (typeclass) {
+ case 'I':
+ if (!skipval) {
+ if (*cx == 'u')
+ thisval = (uint)garglist[gargnum]._uint;
+ else if (*cx == 's')
+ thisval = (uint)garglist[gargnum]._sint;
+ else
+ error("Illegal format string.");
+ }
+ gargnum++;
+ cx++;
+ break;
+ case 'Q':
+ if (!skipval) {
+ opref = garglist[gargnum]._opaqueref;
+ if (opref) {
+ gidispatch_rock_t objrock = gidispatch_get_objrock(opref, *cx - 'a');
+ thisval = ((classref_t *)objrock.ptr)->id;
+ } else {
+ thisval = 0;
+ }
+ }
+ gargnum++;
+ cx++;
+ break;
+ case 'C':
+ if (!skipval) {
+ if (*cx == 'u')
+ thisval = (uint)garglist[gargnum]._uch;
+ else if (*cx == 's')
+ thisval = (uint)garglist[gargnum]._sch;
+ else if (*cx == 'n')
+ thisval = (uint)garglist[gargnum]._ch;
+ else
+ error("Illegal format string.");
+ }
+ gargnum++;
+ cx++;
+ break;
+ case 'S':
+ if (garglist[gargnum]._charstr)
+ ReleaseVMString(garglist[gargnum]._charstr);
+ gargnum++;
+ break;
#ifdef GLK_MODULE_UNICODE
- case 'U':
- if (garglist[gargnum]._unicharstr)
- ReleaseVMUstring(garglist[gargnum]._unicharstr);
- gargnum++;
- break;
+ case 'U':
+ if (garglist[gargnum]._unicharstr)
+ ReleaseVMUstring(garglist[gargnum]._unicharstr);
+ gargnum++;
+ break;
#endif /* GLK_MODULE_UNICODE */
- default:
- error("Illegal format string.");
- break;
- }
-
- if (isreturn) {
- *(splot->retval) = thisval;
- }
- else if (depth > 0) {
- /* Definitely not isref or isarray. */
- if (subpassout)
- WriteStructField(subaddress, ix, thisval);
- }
- else if (isref) {
- if (passout)
- WriteMemory(varglist[ix], thisval);
- }
- }
- }
- else {
- /* We got a null reference, so we have to skip the format element. */
- if (typeclass == '[') {
- int numsubwanted, refdepth;
- numsubwanted = 0;
- while (*cx >= '0' && *cx <= '9') {
- numsubwanted = 10 * numsubwanted + (*cx - '0');
- cx++;
- }
- refdepth = 1;
- while (refdepth > 0) {
- if (*cx == '[')
- refdepth++;
- else if (*cx == ']')
- refdepth--;
- cx++;
- }
- }
- else if (typeclass == 'S' || typeclass == 'U') {
- /* leave it */
- }
- else {
- cx++;
- if (isarray)
- ix++;
- }
- }
- }
-
- if (depth > 0) {
- if (*cx != ']')
- error("Illegal format string.");
- cx++;
- }
- else {
- if (*cx != ':' && *cx != '\0')
- error("Illegal format string.");
- }
-
- *proto = cx;
- *argnumptr = gargnum;
+ default:
+ error("Illegal format string.");
+ break;
+ }
+
+ if (isreturn) {
+ *(splot->retval) = thisval;
+ } else if (depth > 0) {
+ /* Definitely not isref or isarray. */
+ if (subpassout)
+ WriteStructField(subaddress, ix, thisval);
+ } else if (isref) {
+ if (passout)
+ WriteMemory(varglist[ix], thisval);
+ }
+ }
+ } else {
+ /* We got a null reference, so we have to skip the format element. */
+ if (typeclass == '[') {
+ int numsubwanted, refdepth;
+ numsubwanted = 0;
+ while (*cx >= '0' && *cx <= '9') {
+ numsubwanted = 10 * numsubwanted + (*cx - '0');
+ cx++;
+ }
+ refdepth = 1;
+ while (refdepth > 0) {
+ if (*cx == '[')
+ refdepth++;
+ else if (*cx == ']')
+ refdepth--;
+ cx++;
+ }
+ } else if (typeclass == 'S' || typeclass == 'U') {
+ /* leave it */
+ } else {
+ cx++;
+ if (isarray)
+ ix++;
+ }
+ }
+ }
+
+ if (depth > 0) {
+ if (*cx != ']')
+ error("Illegal format string.");
+ cx++;
+ } else {
+ if (*cx != ':' && *cx != '\0')
+ error("Illegal format string.");
+ }
+
+ *proto = cx;
+ *argnumptr = gargnum;
}
strid_t Glulxe::find_stream_by_id(uint objid) {
- if (!objid)
- return nullptr;
+ if (!objid)
+ return nullptr;
- // Recall that class 1 ("b") is streams
- return (strid_t)classes_get(gidisp_Class_Stream, objid);
+ // Recall that class 1 ("b") is streams
+ return (strid_t)classes_get(gidisp_Class_Stream, objid);
}
uint Glulxe::find_id_for_window(winid_t win) {
- gidispatch_rock_t objrock;
+ gidispatch_rock_t objrock;
- if (!win)
- return 0;
+ if (!win)
+ return 0;
- objrock = gidispatch_get_objrock(win, gidisp_Class_Window);
- if (!objrock.ptr)
- return 0;
- return ((classref_t *)objrock.ptr)->id;
+ objrock = gidispatch_get_objrock(win, gidisp_Class_Window);
+ if (!objrock.ptr)
+ return 0;
+ return ((classref_t *)objrock.ptr)->id;
}
uint Glulxe::find_id_for_stream(strid_t str) {
- gidispatch_rock_t objrock;
+ gidispatch_rock_t objrock;
- if (!str)
- return 0;
+ if (!str)
+ return 0;
- objrock = gidispatch_get_objrock(str, gidisp_Class_Stream);
- if (!objrock.ptr)
- return 0;
- return ((classref_t *)objrock.ptr)->id;
+ objrock = gidispatch_get_objrock(str, gidisp_Class_Stream);
+ if (!objrock.ptr)
+ return 0;
+ return ((classref_t *)objrock.ptr)->id;
}
uint Glulxe::find_id_for_fileref(frefid_t fref) {
- gidispatch_rock_t objrock;
+ gidispatch_rock_t objrock;
- if (!fref)
- return 0;
+ if (!fref)
+ return 0;
- objrock = gidispatch_get_objrock(fref, gidisp_Class_Fileref);
- if (!objrock.ptr)
- return 0;
- return ((classref_t *)objrock.ptr)->id;
+ objrock = gidispatch_get_objrock(fref, gidisp_Class_Fileref);
+ if (!objrock.ptr)
+ return 0;
+ return ((classref_t *)objrock.ptr)->id;
}
uint Glulxe::find_id_for_schannel(schanid_t schan) {
- gidispatch_rock_t objrock;
+ gidispatch_rock_t objrock;
- if (!schan)
- return 0;
+ if (!schan)
+ return 0;
- objrock = gidispatch_get_objrock(schan, gidisp_Class_Schannel);
- if (!objrock.ptr)
- return 0;
- return ((classref_t *)objrock.ptr)->id;
+ objrock = gidispatch_get_objrock(schan, gidisp_Class_Schannel);
+ if (!objrock.ptr)
+ return 0;
+ return ((classref_t *)objrock.ptr)->id;
}
classtable_t *Glulxe::new_classtable(uint firstid) {
- int ix;
- classtable_t *ctab = (classtable_t *)glulx_malloc(sizeof(classtable_t));
- if (!ctab)
- return nullptr;
-
- for (ix=0; ix<CLASSHASH_SIZE; ix++)
- ctab->bucket[ix] = nullptr;
-
- ctab->lastid = firstid;
-
- return ctab;
+ int ix;
+ classtable_t *ctab = (classtable_t *)glulx_malloc(sizeof(classtable_t));
+ if (!ctab)
+ return nullptr;
+
+ for (ix = 0; ix < CLASSHASH_SIZE; ix++)
+ ctab->bucket[ix] = nullptr;
+
+ ctab->lastid = firstid;
+
+ return ctab;
}
void *Glulxe::classes_get(int classid, uint objid) {
- classtable_t *ctab;
- classref_t *cref;
- if (classid < 0 || classid >= num_classes)
- return nullptr;
- ctab = classes[classid];
- cref = ctab->bucket[objid % CLASSHASH_SIZE];
- for (; cref; cref = cref->next) {
- if (cref->id == objid)
- return cref->obj;
- }
- return nullptr;
+ classtable_t *ctab;
+ classref_t *cref;
+ if (classid < 0 || classid >= num_classes)
+ return nullptr;
+ ctab = classes[classid];
+ cref = ctab->bucket[objid % CLASSHASH_SIZE];
+ for (; cref; cref = cref->next) {
+ if (cref->id == objid)
+ return cref->obj;
+ }
+ return nullptr;
}
classref_t *Glulxe::classes_put(int classid, void *obj, uint origid) {
- int bucknum;
- classtable_t *ctab;
- classref_t *cref;
- if (classid < 0 || classid >= num_classes)
- return nullptr;
- ctab = classes[classid];
- cref = (classref_t *)glulx_malloc(sizeof(classref_t));
- if (!cref)
- return nullptr;
- cref->obj = obj;
- if (!origid) {
- cref->id = ctab->lastid;
- ctab->lastid++;
- }
- else {
- cref->id = origid;
- if (ctab->lastid <= origid)
- ctab->lastid = origid+1;
- }
- bucknum = cref->id % CLASSHASH_SIZE;
- cref->bucknum = bucknum;
- cref->next = ctab->bucket[bucknum];
- ctab->bucket[bucknum] = cref;
- return cref;
+ int bucknum;
+ classtable_t *ctab;
+ classref_t *cref;
+ if (classid < 0 || classid >= num_classes)
+ return nullptr;
+ ctab = classes[classid];
+ cref = (classref_t *)glulx_malloc(sizeof(classref_t));
+ if (!cref)
+ return nullptr;
+ cref->obj = obj;
+ if (!origid) {
+ cref->id = ctab->lastid;
+ ctab->lastid++;
+ } else {
+ cref->id = origid;
+ if (ctab->lastid <= origid)
+ ctab->lastid = origid + 1;
+ }
+ bucknum = cref->id % CLASSHASH_SIZE;
+ cref->bucknum = bucknum;
+ cref->next = ctab->bucket[bucknum];
+ ctab->bucket[bucknum] = cref;
+ return cref;
}
-void Glulxe::classes_remove(int classid, void *obj)
-{
- classtable_t *ctab;
- classref_t *cref;
- classref_t **crefp;
- gidispatch_rock_t objrock;
- if (classid < 0 || classid >= num_classes)
- return;
- ctab = classes[classid];
- objrock = gidispatch_get_objrock(obj, classid);
- cref = (classref_t *)objrock.ptr;
- if (!cref)
- return;
- crefp = &(ctab->bucket[cref->bucknum]);
- for (; *crefp; crefp = &((*crefp)->next)) {
- if ((*crefp) == cref) {
- *crefp = cref->next;
- if (!cref->obj) {
- nonfatal_warning("attempt to free nullptr object!");
- }
- cref->obj = nullptr;
- cref->id = 0;
- cref->next = nullptr;
- glulx_free(cref);
- return;
- }
- }
- return;
+void Glulxe::classes_remove(int classid, void *obj) {
+ classtable_t *ctab;
+ classref_t *cref;
+ classref_t **crefp;
+ gidispatch_rock_t objrock;
+ if (classid < 0 || classid >= num_classes)
+ return;
+ ctab = classes[classid];
+ objrock = gidispatch_get_objrock(obj, classid);
+ cref = (classref_t *)objrock.ptr;
+ if (!cref)
+ return;
+ crefp = &(ctab->bucket[cref->bucknum]);
+ for (; *crefp; crefp = &((*crefp)->next)) {
+ if ((*crefp) == cref) {
+ *crefp = cref->next;
+ if (!cref->obj) {
+ nonfatal_warning("attempt to free nullptr object!");
+ }
+ cref->obj = nullptr;
+ cref->id = 0;
+ cref->next = nullptr;
+ glulx_free(cref);
+ return;
+ }
+ }
+ return;
}
gidispatch_rock_t Glulxe::glulxe_classtable_register(void *obj, uint objclass) {
- classref_t *cref;
- gidispatch_rock_t objrock;
- cref = classes_put(objclass, obj, 0);
- objrock.ptr = cref;
- return objrock;
+ classref_t *cref;
+ gidispatch_rock_t objrock;
+ cref = classes_put(objclass, obj, 0);
+ objrock.ptr = cref;
+ return objrock;
}
-void Glulxe::glulxe_classtable_unregister(void *obj, uint objclass,
- gidispatch_rock_t objrock) {
- classes_remove(objclass, obj);
+void Glulxe::glulxe_classtable_unregister(void *obj, uint objclass,
+ gidispatch_rock_t objrock) {
+ classes_remove(objclass, obj);
}
gidispatch_rock_t Glulxe::glulxe_classtable_register_existing(void *obj, uint objclass, uint dispid) {
- classref_t *cref;
- gidispatch_rock_t objrock;
- cref = classes_put(objclass, obj, dispid);
- objrock.ptr = cref;
- return objrock;
+ classref_t *cref;
+ gidispatch_rock_t objrock;
+ cref = classes_put(objclass, obj, dispid);
+ objrock.ptr = cref;
+ return objrock;
}
char *Glulxe::grab_temp_c_array(uint addr, uint len, int passin) {
- arrayref_t *arref = nullptr;
- char *arr = nullptr;
- uint ix, addr2;
-
- if (len) {
- arr = (char *)glulx_malloc(len * sizeof(char));
- arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
- if (!arr || !arref)
- error("Unable to allocate space for array argument to Glk call.");
-
- arref->array = arr;
- arref->addr = addr;
- arref->elemsize = 1;
- arref->retained = false;
- arref->len = len;
- arref->next = arrays;
- arrays = arref;
-
- if (passin) {
- for (ix=0, addr2=addr; ix<len; ix++, addr2+=1) {
- arr[ix] = Mem1(addr2);
- }
- }
- }
-
- return arr;
+ arrayref_t *arref = nullptr;
+ char *arr = nullptr;
+ uint ix, addr2;
+
+ if (len) {
+ arr = (char *)glulx_malloc(len * sizeof(char));
+ arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
+ if (!arr || !arref)
+ error("Unable to allocate space for array argument to Glk call.");
+
+ arref->array = arr;
+ arref->addr = addr;
+ arref->elemsize = 1;
+ arref->retained = false;
+ arref->len = len;
+ arref->next = arrays;
+ arrays = arref;
+
+ if (passin) {
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 1) {
+ arr[ix] = Mem1(addr2);
+ }
+ }
+ }
+
+ return arr;
}
void Glulxe::release_temp_c_array(char *arr, uint addr, uint len, int passout) {
- arrayref_t *arref = nullptr;
- arrayref_t **aptr;
- uint ix, val, addr2;
-
- if (arr) {
- for (aptr=(&arrays); (*aptr); aptr=(&((*aptr)->next))) {
- if ((*aptr)->array == arr)
- break;
- }
- arref = *aptr;
- if (!arref)
- error("Unable to re-find array argument in Glk call.");
- if (arref->addr != addr || arref->len != len)
- error("Mismatched array argument in Glk call.");
-
- if (arref->retained) {
- return;
- }
-
- *aptr = arref->next;
- arref->next = nullptr;
-
- if (passout) {
- for (ix=0, addr2=addr; ix<len; ix++, addr2+=1) {
- val = arr[ix];
- MemW1(addr2, val);
- }
- }
- glulx_free(arr);
- glulx_free(arref);
- }
+ arrayref_t *arref = nullptr;
+ arrayref_t **aptr;
+ uint ix, val, addr2;
+
+ if (arr) {
+ for (aptr = (&arrays); (*aptr); aptr = (&((*aptr)->next))) {
+ if ((*aptr)->array == arr)
+ break;
+ }
+ arref = *aptr;
+ if (!arref)
+ error("Unable to re-find array argument in Glk call.");
+ if (arref->addr != addr || arref->len != len)
+ error("Mismatched array argument in Glk call.");
+
+ if (arref->retained) {
+ return;
+ }
+
+ *aptr = arref->next;
+ arref->next = nullptr;
+
+ if (passout) {
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 1) {
+ val = arr[ix];
+ MemW1(addr2, val);
+ }
+ }
+ glulx_free(arr);
+ glulx_free(arref);
+ }
}
uint *Glulxe::grab_temp_i_array(uint addr, uint len, int passin) {
- arrayref_t *arref = nullptr;
- uint *arr = nullptr;
- uint ix, addr2;
-
- if (len) {
- arr = (uint *)glulx_malloc(len * sizeof(uint));
- arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
- if (!arr || !arref)
- error("Unable to allocate space for array argument to Glk call.");
-
- arref->array = arr;
- arref->addr = addr;
- arref->elemsize = 4;
- arref->retained = false;
- arref->len = len;
- arref->next = arrays;
- arrays = arref;
-
- if (passin) {
- for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
- arr[ix] = Mem4(addr2);
- }
- }
- }
-
- return arr;
+ arrayref_t *arref = nullptr;
+ uint *arr = nullptr;
+ uint ix, addr2;
+
+ if (len) {
+ arr = (uint *)glulx_malloc(len * sizeof(uint));
+ arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
+ if (!arr || !arref)
+ error("Unable to allocate space for array argument to Glk call.");
+
+ arref->array = arr;
+ arref->addr = addr;
+ arref->elemsize = 4;
+ arref->retained = false;
+ arref->len = len;
+ arref->next = arrays;
+ arrays = arref;
+
+ if (passin) {
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 4) {
+ arr[ix] = Mem4(addr2);
+ }
+ }
+ }
+
+ return arr;
}
void Glulxe::release_temp_i_array(uint *arr, uint addr, uint len, int passout) {
- arrayref_t *arref = nullptr;
- arrayref_t **aptr;
- uint ix, val, addr2;
-
- if (arr) {
- for (aptr=(&arrays); (*aptr); aptr=(&((*aptr)->next))) {
- if ((*aptr)->array == arr)
- break;
- }
- arref = *aptr;
- if (!arref)
- error("Unable to re-find array argument in Glk call.");
- if (arref->addr != addr || arref->len != len)
- error("Mismatched array argument in Glk call.");
-
- if (arref->retained) {
- return;
- }
-
- *aptr = arref->next;
- arref->next = nullptr;
-
- if (passout) {
- for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
- val = arr[ix];
- MemW4(addr2, val);
- }
- }
- glulx_free(arr);
- glulx_free(arref);
- }
+ arrayref_t *arref = nullptr;
+ arrayref_t **aptr;
+ uint ix, val, addr2;
+
+ if (arr) {
+ for (aptr = (&arrays); (*aptr); aptr = (&((*aptr)->next))) {
+ if ((*aptr)->array == arr)
+ break;
+ }
+ arref = *aptr;
+ if (!arref)
+ error("Unable to re-find array argument in Glk call.");
+ if (arref->addr != addr || arref->len != len)
+ error("Mismatched array argument in Glk call.");
+
+ if (arref->retained) {
+ return;
+ }
+
+ *aptr = arref->next;
+ arref->next = nullptr;
+
+ if (passout) {
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 4) {
+ val = arr[ix];
+ MemW4(addr2, val);
+ }
+ }
+ glulx_free(arr);
+ glulx_free(arref);
+ }
}
void **Glulxe::grab_temp_ptr_array(uint addr, uint len, int objclass, int passin) {
- arrayref_t *arref = nullptr;
- void **arr = nullptr;
- uint ix, addr2;
-
- if (len) {
- arr = (void **)glulx_malloc(len * sizeof(void *));
- arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
- if (!arr || !arref)
- error("Unable to allocate space for array argument to Glk call.");
-
- arref->array = arr;
- arref->addr = addr;
- arref->elemsize = sizeof(void *);
- arref->retained = false;
- arref->len = len;
- arref->next = arrays;
- arrays = arref;
-
- if (passin) {
- for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
- uint thisval = Mem4(addr2);
- if (thisval)
- arr[ix] = classes_get(objclass, thisval);
- else
- arr[ix] = nullptr;
- }
- }
- }
-
- return arr;
+ arrayref_t *arref = nullptr;
+ void **arr = nullptr;
+ uint ix, addr2;
+
+ if (len) {
+ arr = (void **)glulx_malloc(len * sizeof(void *));
+ arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
+ if (!arr || !arref)
+ error("Unable to allocate space for array argument to Glk call.");
+
+ arref->array = arr;
+ arref->addr = addr;
+ arref->elemsize = sizeof(void *);
+ arref->retained = false;
+ arref->len = len;
+ arref->next = arrays;
+ arrays = arref;
+
+ if (passin) {
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 4) {
+ uint thisval = Mem4(addr2);
+ if (thisval)
+ arr[ix] = classes_get(objclass, thisval);
+ else
+ arr[ix] = nullptr;
+ }
+ }
+ }
+
+ return arr;
}
void Glulxe::release_temp_ptr_array(void **arr, uint addr, uint len, int objclass, int passout) {
- arrayref_t *arref = nullptr;
- arrayref_t **aptr;
- uint ix, val, addr2;
-
- if (arr) {
- for (aptr=(&arrays); (*aptr); aptr=(&((*aptr)->next))) {
- if ((*aptr)->array == arr)
- break;
- }
- arref = *aptr;
- if (!arref)
- error("Unable to re-find array argument in Glk call.");
- if (arref->addr != addr || arref->len != len)
- error("Mismatched array argument in Glk call.");
-
- if (arref->retained) {
- return;
- }
-
- *aptr = arref->next;
- arref->next = nullptr;
-
- if (passout) {
- for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
- void *opref = arr[ix];
- if (opref) {
- gidispatch_rock_t objrock =
- gidispatch_get_objrock(opref, objclass);
- val = ((classref_t *)objrock.ptr)->id;
- }
- else {
- val = 0;
- }
- MemW4(addr2, val);
- }
- }
- glulx_free(arr);
- glulx_free(arref);
- }
+ arrayref_t *arref = nullptr;
+ arrayref_t **aptr;
+ uint ix, val, addr2;
+
+ if (arr) {
+ for (aptr = (&arrays); (*aptr); aptr = (&((*aptr)->next))) {
+ if ((*aptr)->array == arr)
+ break;
+ }
+ arref = *aptr;
+ if (!arref)
+ error("Unable to re-find array argument in Glk call.");
+ if (arref->addr != addr || arref->len != len)
+ error("Mismatched array argument in Glk call.");
+
+ if (arref->retained) {
+ return;
+ }
+
+ *aptr = arref->next;
+ arref->next = nullptr;
+
+ if (passout) {
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 4) {
+ void *opref = arr[ix];
+ if (opref) {
+ gidispatch_rock_t objrock =
+ gidispatch_get_objrock(opref, objclass);
+ val = ((classref_t *)objrock.ptr)->id;
+ } else {
+ val = 0;
+ }
+ MemW4(addr2, val);
+ }
+ }
+ glulx_free(arr);
+ glulx_free(arref);
+ }
}
gidispatch_rock_t Glulxe::glulxe_retained_register(void *array, uint len, char *typecode) {
- gidispatch_rock_t rock;
- arrayref_t *arref = nullptr;
- arrayref_t **aptr;
- uint elemsize = 0;
-
- if (typecode[4] == 'C')
- elemsize = 1;
- else if (typecode[4] == 'I')
- elemsize = 4;
-
- if (!elemsize || array == nullptr) {
- rock.ptr = nullptr;
- return rock;
- }
-
- for (aptr=(&arrays); (*aptr); aptr=(&((*aptr)->next))) {
- if ((*aptr)->array == array)
- break;
- }
- arref = *aptr;
- if (!arref)
- error("Unable to re-find array argument in Glk call.");
- if (arref->elemsize != elemsize || arref->len != len)
- error("Mismatched array argument in Glk call.");
-
- arref->retained = true;
-
- rock.ptr = arref;
- return rock;
+ gidispatch_rock_t rock;
+ arrayref_t *arref = nullptr;
+ arrayref_t **aptr;
+ uint elemsize = 0;
+
+ if (typecode[4] == 'C')
+ elemsize = 1;
+ else if (typecode[4] == 'I')
+ elemsize = 4;
+
+ if (!elemsize || array == nullptr) {
+ rock.ptr = nullptr;
+ return rock;
+ }
+
+ for (aptr = (&arrays); (*aptr); aptr = (&((*aptr)->next))) {
+ if ((*aptr)->array == array)
+ break;
+ }
+ arref = *aptr;
+ if (!arref)
+ error("Unable to re-find array argument in Glk call.");
+ if (arref->elemsize != elemsize || arref->len != len)
+ error("Mismatched array argument in Glk call.");
+
+ arref->retained = true;
+
+ rock.ptr = arref;
+ return rock;
}
void Glulxe::glulxe_retained_unregister(void *array, uint len, char *typecode, gidispatch_rock_t objrock) {
- arrayref_t *arref = nullptr;
- arrayref_t **aptr;
- uint ix, addr2, val;
- uint elemsize = 0;
-
- if (typecode[4] == 'C')
- elemsize = 1;
- else if (typecode[4] == 'I')
- elemsize = 4;
-
- if (!elemsize || array == nullptr) {
- return;
- }
-
- for (aptr=(&arrays); (*aptr); aptr=(&((*aptr)->next))) {
- if ((*aptr)->array == array)
- break;
- }
- arref = *aptr;
- if (!arref)
- error("Unable to re-find array argument in Glk call.");
- if (arref != objrock.ptr)
- error("Mismatched array reference in Glk call.");
- if (!arref->retained)
- error("Unretained array reference in Glk call.");
- if (arref->elemsize != elemsize || arref->len != len)
- error("Mismatched array argument in Glk call.");
-
- *aptr = arref->next;
- arref->next = nullptr;
-
- if (elemsize == 1) {
- for (ix=0, addr2=arref->addr; ix<arref->len; ix++, addr2+=1) {
- val = ((char *)array)[ix];
- MemW1(addr2, val);
- }
- }
- else if (elemsize == 4) {
- for (ix=0, addr2=arref->addr; ix<arref->len; ix++, addr2+=4) {
- val = ((uint *)array)[ix];
- MemW4(addr2, val);
- }
- }
-
- glulx_free(array);
- glulx_free(arref);
+ arrayref_t *arref = nullptr;
+ arrayref_t **aptr;
+ uint ix, addr2, val;
+ uint elemsize = 0;
+
+ if (typecode[4] == 'C')
+ elemsize = 1;
+ else if (typecode[4] == 'I')
+ elemsize = 4;
+
+ if (!elemsize || array == nullptr) {
+ return;
+ }
+
+ for (aptr = (&arrays); (*aptr); aptr = (&((*aptr)->next))) {
+ if ((*aptr)->array == array)
+ break;
+ }
+ arref = *aptr;
+ if (!arref)
+ error("Unable to re-find array argument in Glk call.");
+ if (arref != objrock.ptr)
+ error("Mismatched array reference in Glk call.");
+ if (!arref->retained)
+ error("Unretained array reference in Glk call.");
+ if (arref->elemsize != elemsize || arref->len != len)
+ error("Mismatched array argument in Glk call.");
+
+ *aptr = arref->next;
+ arref->next = nullptr;
+
+ if (elemsize == 1) {
+ for (ix = 0, addr2 = arref->addr; ix < arref->len; ix++, addr2 += 1) {
+ val = ((char *)array)[ix];
+ MemW1(addr2, val);
+ }
+ } else if (elemsize == 4) {
+ for (ix = 0, addr2 = arref->addr; ix < arref->len; ix++, addr2 += 4) {
+ val = ((uint *)array)[ix];
+ MemW4(addr2, val);
+ }
+ }
+
+ glulx_free(array);
+ glulx_free(arref);
}
long Glulxe::glulxe_array_locate(void *array, uint len, char *typecode, gidispatch_rock_t objrock, int *elemsizeref) {
- arrayref_t *arref = nullptr;
- arrayref_t **aptr;
- uint elemsize = 0;
-
- if (typecode[4] == 'C')
- elemsize = 1;
- else if (typecode[4] == 'I')
- elemsize = 4;
-
- if (!elemsize || array == nullptr) {
- *elemsizeref = 0; /* No need to save the array separately */
- return (unsigned char *)array - memmap;
- }
-
- for (aptr=(&arrays); (*aptr); aptr=(&((*aptr)->next))) {
- if ((*aptr)->array == array)
- break;
- }
- arref = *aptr;
- if (!arref)
- error("Unable to re-find array argument in array_locate.");
- if (arref != objrock.ptr)
- error("Mismatched array reference in array_locate.");
- if (!arref->retained)
- error("Unretained array reference in array_locate.");
- if (arref->elemsize != elemsize || arref->len != len)
- error("Mismatched array argument in array_locate.");
-
- *elemsizeref = arref->elemsize;
- return arref->addr;
+ arrayref_t *arref = nullptr;
+ arrayref_t **aptr;
+ uint elemsize = 0;
+
+ if (typecode[4] == 'C')
+ elemsize = 1;
+ else if (typecode[4] == 'I')
+ elemsize = 4;
+
+ if (!elemsize || array == nullptr) {
+ *elemsizeref = 0; /* No need to save the array separately */
+ return (unsigned char *)array - memmap;
+ }
+
+ for (aptr = (&arrays); (*aptr); aptr = (&((*aptr)->next))) {
+ if ((*aptr)->array == array)
+ break;
+ }
+ arref = *aptr;
+ if (!arref)
+ error("Unable to re-find array argument in array_locate.");
+ if (arref != objrock.ptr)
+ error("Mismatched array reference in array_locate.");
+ if (!arref->retained)
+ error("Unretained array reference in array_locate.");
+ if (arref->elemsize != elemsize || arref->len != len)
+ error("Mismatched array argument in array_locate.");
+
+ *elemsizeref = arref->elemsize;
+ return arref->addr;
}
gidispatch_rock_t Glulxe::glulxe_array_restore(long bufkey, uint len, char *typecode, void **arrayref) {
- gidispatch_rock_t rock;
- int elemsize = 0;
-
- if (typecode[4] == 'C')
- elemsize = 1;
- else if (typecode[4] == 'I')
- elemsize = 4;
-
- if (!elemsize) {
- unsigned char *buf = memmap + bufkey;
- *arrayref = buf;
- rock.ptr = nullptr;
- return rock;
- }
-
- if (elemsize == 1) {
- char *cbuf = grab_temp_c_array(bufkey, len, false);
- rock = glulxe_retained_register(cbuf, len, typecode);
- *arrayref = cbuf;
- }
- else {
- uint *ubuf = grab_temp_i_array(bufkey, len, false);
- rock = glulxe_retained_register(ubuf, len, typecode);
- *arrayref = ubuf;
- }
- return rock;
+ gidispatch_rock_t rock;
+ int elemsize = 0;
+
+ if (typecode[4] == 'C')
+ elemsize = 1;
+ else if (typecode[4] == 'I')
+ elemsize = 4;
+
+ if (!elemsize) {
+ unsigned char *buf = memmap + bufkey;
+ *arrayref = buf;
+ rock.ptr = nullptr;
+ return rock;
+ }
+
+ if (elemsize == 1) {
+ char *cbuf = grab_temp_c_array(bufkey, len, false);
+ rock = glulxe_retained_register(cbuf, len, typecode);
+ *arrayref = cbuf;
+ } else {
+ uint *ubuf = grab_temp_i_array(bufkey, len, false);
+ rock = glulxe_retained_register(ubuf, len, typecode);
+ *arrayref = ubuf;
+ }
+ return rock;
}
void Glulxe::set_library_select_hook(void (*func)(uint)) {
- library_select_hook = func;
+ library_select_hook = func;
}
char *Glulxe::get_game_id() {
- /* This buffer gets rewritten on every call, but that's okay -- the caller
- is supposed to copy out the result. */
- static char buf[2*64+2];
- int ix, jx;
-
- if (!memmap)
- return nullptr;
-
- for (ix=0, jx=0; ix<64; ix++) {
- char ch = memmap[ix];
- int val = ((ch >> 4) & 0x0F);
- buf[jx++] = ((val < 10) ? (val + '0') : (val + 'A' - 10));
- val = (ch & 0x0F);
- buf[jx++] = ((val < 10) ? (val + '0') : (val + 'A' - 10));
- }
- buf[jx++] = '\0';
-
- return buf;
+ /* This buffer gets rewritten on every call, but that's okay -- the caller
+ is supposed to copy out the result. */
+ static char buf[2 * 64 + 2];
+ int ix, jx;
+
+ if (!memmap)
+ return nullptr;
+
+ for (ix = 0, jx = 0; ix < 64; ix++) {
+ char ch = memmap[ix];
+ int val = ((ch >> 4) & 0x0F);
+ buf[jx++] = ((val < 10) ? (val + '0') : (val + 'A' - 10));
+ val = (ch & 0x0F);
+ buf[jx++] = ((val < 10) ? (val + '0') : (val + 'A' - 10));
+ }
+ buf[jx++] = '\0';
+
+ return buf;
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/glulxe.cpp b/engines/glk/glulxe/glulxe.cpp
index 5d4420b203..a78e22cea4 100644
--- a/engines/glk/glulxe/glulxe.cpp
+++ b/engines/glk/glulxe/glulxe.cpp
@@ -30,23 +30,23 @@ namespace Glulxe {
Glulxe *g_vm;
Glulxe::Glulxe(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), _random("glulxe"),
- vm_exited_cleanly(false), gamefile_start(0), gamefile_len(0), memmap(nullptr), stack(nullptr),
- ramstart(0), endgamefile(0), origendmem(0), stacksize(0), startfuncaddr(0), checksum(0),
- stackptr(0), frameptr(0), pc(0), prevpc(0), origstringtable(0), stringtable(0), valstackbase(0),
- localsbase(0), endmem(0), protectstart(0), protectend(0),
- stream_char_handler(nullptr), stream_unichar_handler(nullptr),
- // main
- library_autorestore_hook(nullptr),
- // accel
- classes_table(0), indiv_prop_start(0), class_metaclass(0), object_metaclass(0),
- routine_metaclass(0), string_metaclass(0), self(0), num_attr_bytes(0), cpv__start(0),
- accelentries(nullptr),
- // heap
- heap_start(0), alloc_count(0), heap_head(nullptr), heap_tail(nullptr),
- // serial
- max_undo_level(8), undo_chain_size(0), undo_chain_num(0), undo_chain(nullptr), ramcache(nullptr),
- // string
- iosys_mode(0), iosys_rock(0), tablecache_valid(false), glkio_unichar_han_ptr(nullptr) {
+ vm_exited_cleanly(false), gamefile_start(0), gamefile_len(0), memmap(nullptr), stack(nullptr),
+ ramstart(0), endgamefile(0), origendmem(0), stacksize(0), startfuncaddr(0), checksum(0),
+ stackptr(0), frameptr(0), pc(0), prevpc(0), origstringtable(0), stringtable(0), valstackbase(0),
+ localsbase(0), endmem(0), protectstart(0), protectend(0),
+ stream_char_handler(nullptr), stream_unichar_handler(nullptr),
+ // main
+ library_autorestore_hook(nullptr),
+ // accel
+ classes_table(0), indiv_prop_start(0), class_metaclass(0), object_metaclass(0),
+ routine_metaclass(0), string_metaclass(0), self(0), num_attr_bytes(0), cpv__start(0),
+ accelentries(nullptr),
+ // heap
+ heap_start(0), alloc_count(0), heap_head(nullptr), heap_tail(nullptr),
+ // serial
+ max_undo_level(8), undo_chain_size(0), undo_chain_num(0), undo_chain(nullptr), ramcache(nullptr),
+ // string
+ iosys_mode(0), iosys_rock(0), tablecache_valid(false), glkio_unichar_han_ptr(nullptr) {
g_vm = this;
}
diff --git a/engines/glk/glulxe/glulxe.h b/engines/glk/glulxe/glulxe.h
index d9003c851e..b985beb7c4 100644
--- a/engines/glk/glulxe/glulxe.h
+++ b/engines/glk/glulxe/glulxe.h
@@ -78,10 +78,10 @@ private:
* @{
*/
- /**
- * The library_autorestore_hook is called right after the VM's initial setup. This is an appropriate time
- * to autorestore an initial game state, if the library has that capability. (Currently, only iosglk does.)
- */
+ /**
+ * The library_autorestore_hook is called right after the VM's initial setup. This is an appropriate time
+ * to autorestore an initial game state, if the library has that capability. (Currently, only iosglk does.)
+ */
void(*library_autorestore_hook)(void);
Common::RandomSource _random;
@@ -110,7 +110,7 @@ private:
* @{
*/
- uint heap_start; ///< zero for inactive heap
+ uint heap_start; ///< zero for inactive heap
int alloc_count;
/* The heap_head/heap_tail is a doubly-linked list of blocks, both
@@ -151,9 +151,9 @@ private:
* @{
*/
- /**
- * This can be adjusted before startup by platform-specific startup code -- that is, preference code.
- */
+ /**
+ * This can be adjusted before startup by platform-specific startup code -- that is, preference code.
+ */
int max_undo_level;
int undo_chain_size;
@@ -182,7 +182,7 @@ private:
cacheblock_t tablecache;
/* This misbehaves if a Glk function has more than one S argument. */
- #define STATIC_TEMP_BUFSIZE (127)
+#define STATIC_TEMP_BUFSIZE (127)
char temp_buf[STATIC_TEMP_BUFSIZE + 1];
/**@}*/
@@ -253,7 +253,7 @@ protected:
*/
uint get_prop_new(uint obj, uint id);
- /**@}*/
+ /**@}*/
/**
* \defgroup glkop support methods
@@ -302,12 +302,12 @@ protected:
* to deal with structures.
*/
void parse_glk_args(dispatch_splot_t *splot, const char **proto, int depth, int *argnumptr, uint subaddress, int subpassin);
-
+
/**
* This is about the reverse of parse_glk_args().
*/
void unparse_glk_args(dispatch_splot_t *splot, const char **proto, int depth,
- int *argnumptr, uint subaddress, int subpassout);
+ int *argnumptr, uint subaddress, int subpassout);
/**
* Create a string identifying this game. We use the first 64 bytes of the memory map, encoded as hex,
@@ -389,7 +389,9 @@ public:
/**
* Returns the running interpreter type
*/
- virtual InterpreterType getInterpreterType() const override { return INTERPRETER_GLULXE; }
+ virtual InterpreterType getInterpreterType() const override {
+ return INTERPRETER_GLULXE;
+ }
/**
* Load a savegame from the passed stream
@@ -427,9 +429,9 @@ public:
* @{
*/
- /**
- * Validates the game file, and if it's invalid, displays an error dialog
- */
+ /**
+ * Validates the game file, and if it's invalid, displays an error dialog
+ */
bool is_gamefile_valid();
/**@}*/
@@ -439,16 +441,16 @@ public:
* @{
*/
- /**
- * Read in the game file and build the machine, allocating all the memory necessary.
- */
+ /**
+ * Read in the game file and build the machine, allocating all the memory necessary.
+ */
void setup_vm();
/**
* Deallocate all the memory and shut down the machine.
*/
void finalize_vm();
-
+
/**
* Put the VM into a state where it's ready to begin executing the game. This is called
* both at startup time, and when the machine performs a "restart" opcode.
@@ -461,14 +463,14 @@ public:
* when the heap-allocation system is calling. Returns 0 for success; otherwise, the operation failed.
*/
uint change_memsize(uint newlen, bool internal);
-
+
/**
* If addr is 0, pop N arguments off the stack, and put them in an array. If non-0, take N arguments
* from that main memory address instead. This has to dynamically allocate if there are more than
* 32 arguments, but that shouldn't be a problem.
*/
uint *pop_arguments(uint count, uint addr);
-
+
/**
* Make sure that count bytes beginning with addr all fall within the current memory map.
* This is called at every memory (read) access if VERIFY_MEMORY_ACCESS is defined in the header file.
@@ -495,9 +497,9 @@ public:
* @{
*/
- /**
- * The main interpreter loop. This repeats until the program is done
- */
+ /**
+ * The main interpreter loop. This repeats until the program is done
+ */
void execute_loop();
/**@}*/
@@ -507,9 +509,9 @@ public:
* @{
*/
- /**
- * Set up the fast-lookup array of operandlists. This is called just once, when the terp starts up.
- */
+ /**
+ * Set up the fast-lookup array of operandlists. This is called just once, when the terp starts up.
+ */
void init_operands();
/**
@@ -549,7 +551,7 @@ public:
* Note that if argc is zero, argv may be nullptr.
*/
void enter_function(uint addr, uint argc, uint *argv);
-
+
/**
* Pop the current call frame off the stack. This is very simple.
*/
@@ -610,11 +612,11 @@ public:
/**
* Create an array of words, in the VM serialization format:
*
- * heap_start
- * alloc_count
- * addr of first block
- * len of first block
- * ...
+ * heap_start
+ * alloc_count
+ * addr of first block
+ * len of first block
+ * ...
*
* (Note that these are uint values -- native byte ordering. Also, the blocks will be in address order,
* which is a stricter guarantee than the VM specifies; that'll help in heap_apply_summary().)
@@ -649,19 +651,19 @@ public:
*/
- /**
- * An array of data structures is stored in memory, beginning at start, each structure being structsize bytes.
- * Within each struct, there is a key value keysize bytes long, starting at position keyoffset (from
- * the start of the structure.) Search through these in order. If one is found whose key matches, return it.
- * If numstructs are searched with no result, return nullptr.
- *
- * numstructs may be -1 (0xFFFFFFFF) to indicate no upper limit to the number of structures to search.
- * The search will continue until a match is found, or (if ZeroKeyTerminates is set) a zero key.
- *
- * The KeyIndirect, ZeroKeyTerminates, and ReturnIndex options may be used.
- */
+ /**
+ * An array of data structures is stored in memory, beginning at start, each structure being structsize bytes.
+ * Within each struct, there is a key value keysize bytes long, starting at position keyoffset (from
+ * the start of the structure.) Search through these in order. If one is found whose key matches, return it.
+ * If numstructs are searched with no result, return nullptr.
+ *
+ * numstructs may be -1 (0xFFFFFFFF) to indicate no upper limit to the number of structures to search.
+ * The search will continue until a match is found, or (if ZeroKeyTerminates is set) a zero key.
+ *
+ * The KeyIndirect, ZeroKeyTerminates, and ReturnIndex options may be used.
+ */
uint linear_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
- uint keyoffset, uint options);
+ uint keyoffset, uint options);
/**
* An array of data structures is in memory, as above. However, the structs must be stored in forward
@@ -671,7 +673,7 @@ public:
* The KeyIndirect and ReturnIndex options may be used.
*/
uint binary_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
- uint keyoffset, uint options);
+ uint keyoffset, uint options);
/**
* The structures may be anywhere in memory, in any order. They are linked by a four-byte address field,
@@ -723,9 +725,9 @@ public:
* @{
*/
- /**
- * glkop section initialization
- */
+ /**
+ * glkop section initialization
+ */
void glkopInit();
void set_library_select_hook(void(*func)(uint));
@@ -754,7 +756,7 @@ public:
* Read the prefixes of an argument string -- the "<>&+:#!" chars.
*/
const char *read_prefix(const char *cx, int *isref, int *isarray, int *passin, int *passout,
- int *nullok, int *isretained, int *isreturn);
+ int *nullok, int *isretained, int *isreturn);
/**
* This is used by some interpreter code which has to, well, find a Glk stream given its ID.
@@ -868,9 +870,11 @@ public:
that it can reinterpret-cast IEEE-754 int values into gfloat32
values. If you uncomment this, Glulxe switches to lengthier
(but safer) encoding and decoding functions. */
- /* #define FLOAT_NOT_NATIVE (1) */
+ /* #define FLOAT_NOT_NATIVE (1) */
- int init_float() { return true; }
+ int init_float() {
+ return true;
+ }
/**
* Encode floats by a lot of annoying bit manipulation.
@@ -887,7 +891,7 @@ public:
/* Uncomment this definition if your powf() function does not support
all the corner cases specified by C99. If you uncomment this,
osdepend.c will provide a safer implementation of glulx_powf(). */
- /* #define FLOAT_COMPILE_SAFER_POWF (1) */
+ /* #define FLOAT_COMPILE_SAFER_POWF (1) */
inline gfloat32 glulx_powf(gfloat32 val1, gfloat32 val2) const {
return powf(val1, val2);
@@ -901,9 +905,9 @@ public:
* @{
*/
- /**
- * Set up the undo chain and anything else that needs to be set up.
- */
+ /**
+ * Set up the undo chain and anything else that needs to be set up.
+ */
bool init_serial();
/**
@@ -946,9 +950,9 @@ public:
* @{
*/
- /**
- * Write a signed integer to the current output stream.
- */
+ /**
+ * Write a signed integer to the current output stream.
+ */
void stream_num(int val, int inmiddle, int charnum);
/**
diff --git a/engines/glk/glulxe/glulxe_types.h b/engines/glk/glulxe/glulxe_types.h
index 9200ec27eb..d57600edb7 100644
--- a/engines/glk/glulxe/glulxe_types.h
+++ b/engines/glk/glulxe/glulxe_types.h
@@ -103,18 +103,18 @@ class Glulxe;
* degradation or even crashes, depending on the machine CPU.
*/
#define Stk1(adr) \
- (*((unsigned char *)(stack+(adr))))
+ (*((unsigned char *)(stack+(adr))))
#define Stk2(adr) \
- (*((uint16 *)(stack+(adr))))
+ (*((uint16 *)(stack+(adr))))
#define Stk4(adr) \
- (*((uint32 *)(stack+(adr))))
+ (*((uint32 *)(stack+(adr))))
#define StkW1(adr, vl) \
- (*((byte *)(stack+(adr))) = (byte)(vl))
+ (*((byte *)(stack+(adr))) = (byte)(vl))
#define StkW2(adr, vl) \
- (*((uint16 *)(stack+(adr))) = (uint16)(vl))
+ (*((uint16 *)(stack+(adr))) = (uint16)(vl))
#define StkW4(adr, vl) \
- (*((uint32 *)(stack+(adr))) = (uint32)(vl))
+ (*((uint32 *)(stack+(adr))) = (uint32)(vl))
enum Opcode {
op_nop = 0x00,
@@ -319,9 +319,9 @@ typedef classtable_struct classtable_t;
* Represents the operand structure of an opcode.
*/
struct operandlist_struct {
- int num_ops; ///< Number of operands for this opcode
- int arg_size; ///< Usually 4, but can be 1 or 2
- const int *formlist; ///< Array of values, either modeform_Load or modeform_Store
+ int num_ops; ///< Number of operands for this opcode
+ int arg_size; ///< Usually 4, but can be 1 or 2
+ const int *formlist; ///< Array of values, either modeform_Load or modeform_Store
};
typedef operandlist_struct operandlist_t;
@@ -389,7 +389,7 @@ enum iosys {
};
#define CACHEBITS (4)
-#define CACHESIZE (1 << CACHEBITS)
+#define CACHESIZE (1 << CACHEBITS)
#define CACHEMASK (15)
struct cacheblock_struct {
diff --git a/engines/glk/glulxe/heap.cpp b/engines/glk/glulxe/heap.cpp
index 00b8dcb74c..86cd4439b8 100644
--- a/engines/glk/glulxe/heap.cpp
+++ b/engines/glk/glulxe/heap.cpp
@@ -26,295 +26,290 @@ namespace Glk {
namespace Glulxe {
void Glulxe::heap_clear() {
- while (heap_head) {
- heapblock_t *blo = heap_head;
- heap_head = blo->next;
- blo->next = nullptr;
- blo->prev = nullptr;
- glulx_free(blo);
- }
- heap_tail = nullptr;
-
- if (heap_start) {
- uint res = change_memsize(heap_start, true);
- if (res)
- fatal_error_i("Unable to revert memory size when deactivating heap.",
- heap_start);
- }
-
- heap_start = 0;
- alloc_count = 0;
- /* heap_sanity_check(); */
+ while (heap_head) {
+ heapblock_t *blo = heap_head;
+ heap_head = blo->next;
+ blo->next = nullptr;
+ blo->prev = nullptr;
+ glulx_free(blo);
+ }
+ heap_tail = nullptr;
+
+ if (heap_start) {
+ uint res = change_memsize(heap_start, true);
+ if (res)
+ fatal_error_i("Unable to revert memory size when deactivating heap.",
+ heap_start);
+ }
+
+ heap_start = 0;
+ alloc_count = 0;
+ /* heap_sanity_check(); */
}
int Glulxe::heap_is_active() const {
- return (heap_start != 0);
+ return (heap_start != 0);
}
uint Glulxe::heap_get_start() const {
- return heap_start;
+ return heap_start;
}
uint Glulxe::heap_alloc(uint len) {
- heapblock_t *blo, *newblo;
+ heapblock_t *blo, *newblo;
#ifdef FIXED_MEMSIZE
- return 0;
+ return 0;
#else /* FIXED_MEMSIZE */
- if (len <= 0)
- fatal_error("Heap allocation length must be positive.");
-
- blo = heap_head;
- while (blo) {
- if (blo->isfree && blo->len >= len)
- break;
-
- if (!blo->isfree) {
- blo = blo->next;
- continue;
- }
-
- if (!blo->next || !blo->next->isfree) {
- blo = blo->next;
- continue;
- }
-
- /* This is a free block, but the next block in the list is also
- free, so we "advance" by merging rather than by going to
- blo->next. */
- newblo = blo->next;
- blo->len += newblo->len;
- if (newblo->next) {
- blo->next = newblo->next;
- newblo->next->prev = blo;
- }
- else {
- blo->next = nullptr;
- heap_tail = blo;
- }
- newblo->next = nullptr;
- newblo->prev = nullptr;
- glulx_free(newblo);
- newblo = nullptr;
- continue;
- }
-
- if (!blo) {
- /* No free area is visible on the list. Try extending memory. How
- much? Double the heap size, or by 256 bytes, or by the memory
- length requested -- whichever is greatest. */
- uint res;
- uint extension;
- uint oldendmem = endmem;
-
- extension = 0;
- if (heap_start)
- extension = endmem - heap_start;
- if (extension < len)
- extension = len;
- if (extension < 256)
- extension = 256;
- /* And it must be rounded up to a multiple of 256. */
- extension = (extension + 0xFF) & (~(uint)0xFF);
-
- res = change_memsize(endmem+extension, true);
- if (res)
- return 0;
-
- /* If we just started the heap, note that. */
- if (heap_start == 0)
- heap_start = oldendmem;
-
- if (heap_tail && heap_tail->isfree) {
- /* Append the new space to the last block. */
- blo = heap_tail;
- blo->len += extension;
- }
- else {
- /* Append the new space to the block list, as a new block. */
- newblo = (heapblock_t *)glulx_malloc(sizeof(heapblock_t));
- if (!newblo)
- fatal_error("Unable to allocate record for heap block.");
- newblo->addr = oldendmem;
- newblo->len = extension;
- newblo->isfree = true;
- newblo->next = nullptr;
- newblo->prev = nullptr;
-
- if (!heap_tail) {
- heap_head = newblo;
- heap_tail = newblo;
- }
- else {
- blo = heap_tail;
- heap_tail = newblo;
- blo->next = newblo;
- newblo->prev = blo;
- }
-
- blo = newblo;
- newblo = nullptr;
- }
-
- /* and continue forwards, using this new block (blo). */
- }
-
- /* Something strange happened. */
- if (!blo || !blo->isfree || blo->len < len)
- return 0;
-
- /* We now have a free block of size len or longer. */
-
- if (blo->len == len) {
- blo->isfree = false;
- }
- else {
- newblo = (heapblock_t *)glulx_malloc(sizeof(heapblock_t));
- if (!newblo)
- fatal_error("Unable to allocate record for heap block.");
- newblo->isfree = true;
- newblo->addr = blo->addr + len;
- newblo->len = blo->len - len;
- blo->len = len;
- blo->isfree = false;
- newblo->next = blo->next;
- if (newblo->next)
- newblo->next->prev = newblo;
- newblo->prev = blo;
- blo->next = newblo;
- if (heap_tail == blo)
- heap_tail = newblo;
- }
-
- alloc_count++;
- /* heap_sanity_check(); */
- return blo->addr;
+ if (len <= 0)
+ fatal_error("Heap allocation length must be positive.");
+
+ blo = heap_head;
+ while (blo) {
+ if (blo->isfree && blo->len >= len)
+ break;
+
+ if (!blo->isfree) {
+ blo = blo->next;
+ continue;
+ }
+
+ if (!blo->next || !blo->next->isfree) {
+ blo = blo->next;
+ continue;
+ }
+
+ /* This is a free block, but the next block in the list is also
+ free, so we "advance" by merging rather than by going to
+ blo->next. */
+ newblo = blo->next;
+ blo->len += newblo->len;
+ if (newblo->next) {
+ blo->next = newblo->next;
+ newblo->next->prev = blo;
+ } else {
+ blo->next = nullptr;
+ heap_tail = blo;
+ }
+ newblo->next = nullptr;
+ newblo->prev = nullptr;
+ glulx_free(newblo);
+ newblo = nullptr;
+ continue;
+ }
+
+ if (!blo) {
+ /* No free area is visible on the list. Try extending memory. How
+ much? Double the heap size, or by 256 bytes, or by the memory
+ length requested -- whichever is greatest. */
+ uint res;
+ uint extension;
+ uint oldendmem = endmem;
+
+ extension = 0;
+ if (heap_start)
+ extension = endmem - heap_start;
+ if (extension < len)
+ extension = len;
+ if (extension < 256)
+ extension = 256;
+ /* And it must be rounded up to a multiple of 256. */
+ extension = (extension + 0xFF) & (~(uint)0xFF);
+
+ res = change_memsize(endmem + extension, true);
+ if (res)
+ return 0;
+
+ /* If we just started the heap, note that. */
+ if (heap_start == 0)
+ heap_start = oldendmem;
+
+ if (heap_tail && heap_tail->isfree) {
+ /* Append the new space to the last block. */
+ blo = heap_tail;
+ blo->len += extension;
+ } else {
+ /* Append the new space to the block list, as a new block. */
+ newblo = (heapblock_t *)glulx_malloc(sizeof(heapblock_t));
+ if (!newblo)
+ fatal_error("Unable to allocate record for heap block.");
+ newblo->addr = oldendmem;
+ newblo->len = extension;
+ newblo->isfree = true;
+ newblo->next = nullptr;
+ newblo->prev = nullptr;
+
+ if (!heap_tail) {
+ heap_head = newblo;
+ heap_tail = newblo;
+ } else {
+ blo = heap_tail;
+ heap_tail = newblo;
+ blo->next = newblo;
+ newblo->prev = blo;
+ }
+
+ blo = newblo;
+ newblo = nullptr;
+ }
+
+ /* and continue forwards, using this new block (blo). */
+ }
+
+ /* Something strange happened. */
+ if (!blo || !blo->isfree || blo->len < len)
+ return 0;
+
+ /* We now have a free block of size len or longer. */
+
+ if (blo->len == len) {
+ blo->isfree = false;
+ } else {
+ newblo = (heapblock_t *)glulx_malloc(sizeof(heapblock_t));
+ if (!newblo)
+ fatal_error("Unable to allocate record for heap block.");
+ newblo->isfree = true;
+ newblo->addr = blo->addr + len;
+ newblo->len = blo->len - len;
+ blo->len = len;
+ blo->isfree = false;
+ newblo->next = blo->next;
+ if (newblo->next)
+ newblo->next->prev = newblo;
+ newblo->prev = blo;
+ blo->next = newblo;
+ if (heap_tail == blo)
+ heap_tail = newblo;
+ }
+
+ alloc_count++;
+ /* heap_sanity_check(); */
+ return blo->addr;
#endif /* FIXED_MEMSIZE */
}
void Glulxe::heap_free(uint addr) {
- heapblock_t *blo;
-
- for (blo = heap_head; blo; blo = blo->next) {
- if (blo->addr == addr)
- break;
- };
- if (!blo || blo->isfree)
- fatal_error_i("Attempt to free unallocated address from heap.", addr);
-
- blo->isfree = true;
- alloc_count--;
- if (alloc_count <= 0) {
- heap_clear();
- }
-
- /* heap_sanity_check(); */
+ heapblock_t *blo;
+
+ for (blo = heap_head; blo; blo = blo->next) {
+ if (blo->addr == addr)
+ break;
+ };
+ if (!blo || blo->isfree)
+ fatal_error_i("Attempt to free unallocated address from heap.", addr);
+
+ blo->isfree = true;
+ alloc_count--;
+ if (alloc_count <= 0) {
+ heap_clear();
+ }
+
+ /* heap_sanity_check(); */
}
int Glulxe::heap_get_summary(uint *valcount, uint **summary) {
- uint *arr, len, pos;
- heapblock_t *blo;
+ uint *arr, len, pos;
+ heapblock_t *blo;
- *valcount = 0;
- *summary = nullptr;
+ *valcount = 0;
+ *summary = nullptr;
- if (heap_start == 0)
- return 0;
+ if (heap_start == 0)
+ return 0;
- len = 2 + 2*alloc_count;
- arr = (uint *)glulx_malloc(len * sizeof(uint));
- if (!arr)
- return 1;
+ len = 2 + 2 * alloc_count;
+ arr = (uint *)glulx_malloc(len * sizeof(uint));
+ if (!arr)
+ return 1;
- pos = 0;
- arr[pos++] = heap_start;
- arr[pos++] = alloc_count;
+ pos = 0;
+ arr[pos++] = heap_start;
+ arr[pos++] = alloc_count;
- for (blo = heap_head; blo; blo = blo->next) {
- if (blo->isfree)
- continue;
- arr[pos++] = blo->addr;
- arr[pos++] = blo->len;
- }
+ for (blo = heap_head; blo; blo = blo->next) {
+ if (blo->isfree)
+ continue;
+ arr[pos++] = blo->addr;
+ arr[pos++] = blo->len;
+ }
- if (pos != len)
- fatal_error("Wrong number of active blocks in heap");
+ if (pos != len)
+ fatal_error("Wrong number of active blocks in heap");
- *valcount = len;
- *summary = arr;
- return 0;
+ *valcount = len;
+ *summary = arr;
+ return 0;
}
int Glulxe::heap_apply_summary(uint valcount, uint *summary) {
- uint lx, jx, lastend;
+ uint lx, jx, lastend;
- if (heap_start)
- fatal_error("Heap active when heap_apply_summary called");
+ if (heap_start)
+ fatal_error("Heap active when heap_apply_summary called");
- if (valcount == 0 || summary == nullptr)
- return 0;
- if (valcount == 2 && summary[0] == 0 && summary[1] == 0)
- return 0;
+ if (valcount == 0 || summary == nullptr)
+ return 0;
+ if (valcount == 2 && summary[0] == 0 && summary[1] == 0)
+ return 0;
#ifdef FIXED_MEMSIZE
- return 1;
+ return 1;
#else /* FIXED_MEMSIZE */
- lx = 0;
- heap_start = summary[lx++];
- alloc_count = summary[lx++];
-
- for (jx=lx; jx+2<valcount; jx+=2) {
- if (summary[jx] >= summary[jx+2])
- fatal_error("Heap block summary is out of order.");
- }
-
- lastend = heap_start;
-
- while (lx < valcount || lastend < endmem) {
- heapblock_t *blo;
-
- blo = (heapblock_t *)glulx_malloc(sizeof(heapblock_t));
- if (!blo)
- fatal_error("Unable to allocate record for heap block.");
-
- if (lx >= valcount) {
- blo->addr = lastend;
- blo->len = endmem - lastend;
- blo->isfree = true;
- } else {
- if (lastend < summary[lx]) {
- blo->addr = lastend;
- blo->len = summary[lx] - lastend;
- blo->isfree = true;
- } else {
- blo->addr = summary[lx++];
- blo->len = summary[lx++];
- blo->isfree = false;
- }
- }
-
- blo->prev = nullptr;
- blo->next = nullptr;
-
- if (!heap_head) {
- heap_head = blo;
- heap_tail = blo;
- }
- else {
- heap_tail->next = blo;
- blo->prev = heap_tail;
- heap_tail = blo;
- }
-
- lastend = blo->addr + blo->len;
- }
-
- /* heap_sanity_check(); */
-
- return 0;
+ lx = 0;
+ heap_start = summary[lx++];
+ alloc_count = summary[lx++];
+
+ for (jx = lx; jx + 2 < valcount; jx += 2) {
+ if (summary[jx] >= summary[jx + 2])
+ fatal_error("Heap block summary is out of order.");
+ }
+
+ lastend = heap_start;
+
+ while (lx < valcount || lastend < endmem) {
+ heapblock_t *blo;
+
+ blo = (heapblock_t *)glulx_malloc(sizeof(heapblock_t));
+ if (!blo)
+ fatal_error("Unable to allocate record for heap block.");
+
+ if (lx >= valcount) {
+ blo->addr = lastend;
+ blo->len = endmem - lastend;
+ blo->isfree = true;
+ } else {
+ if (lastend < summary[lx]) {
+ blo->addr = lastend;
+ blo->len = summary[lx] - lastend;
+ blo->isfree = true;
+ } else {
+ blo->addr = summary[lx++];
+ blo->len = summary[lx++];
+ blo->isfree = false;
+ }
+ }
+
+ blo->prev = nullptr;
+ blo->next = nullptr;
+
+ if (!heap_head) {
+ heap_head = blo;
+ heap_tail = blo;
+ } else {
+ heap_tail->next = blo;
+ blo->prev = heap_tail;
+ heap_tail = blo;
+ }
+
+ lastend = blo->addr + blo->len;
+ }
+
+ /* heap_sanity_check(); */
+
+ return 0;
#endif /* FIXED_MEMSIZE */
}
diff --git a/engines/glk/glulxe/operand.cpp b/engines/glk/glulxe/operand.cpp
index 23018d408f..d41b2b0fe7 100644
--- a/engines/glk/glulxe/operand.cpp
+++ b/engines/glk/glulxe/operand.cpp
@@ -65,552 +65,546 @@ static const int array_LLSS[4] = { modeform_Load, modeform_Load, modeform_Store,
static const operandlist_t list_LLSS = { 4, 4, &array_LLSS[0] };
void Glulxe::init_operands() {
- for (int ix=0; ix<0x80; ix++)
- fast_operandlist[ix] = lookup_operandlist(ix);
+ for (int ix = 0; ix < 0x80; ix++)
+ fast_operandlist[ix] = lookup_operandlist(ix);
}
const operandlist_t *Glulxe::lookup_operandlist(uint opcode) {
- switch (opcode) {
- case op_nop:
- return &list_none;
-
- case op_add:
- case op_sub:
- case op_mul:
- case op_div:
- case op_mod:
- case op_bitand:
- case op_bitor:
- case op_bitxor:
- case op_shiftl:
- case op_sshiftr:
- case op_ushiftr:
- return &list_LLS;
-
- case op_neg:
- case op_bitnot:
- return &list_LS;
-
- case op_jump:
- case op_jumpabs:
- return &list_L;
- case op_jz:
- case op_jnz:
- return &list_LL;
- case op_jeq:
- case op_jne:
- case op_jlt:
- case op_jge:
- case op_jgt:
- case op_jle:
- case op_jltu:
- case op_jgeu:
- case op_jgtu:
- case op_jleu:
- return &list_LLL;
-
- case op_call:
- return &list_LLS;
- case op_return:
- return &list_L;
- case op_catch:
- return &list_SL;
- case op_throw:
- return &list_LL;
- case op_tailcall:
- return &list_LL;
-
- case op_sexb:
- case op_sexs:
- return &list_LS;
-
- case op_copy:
- return &list_LS;
- case op_copys:
- return &list_2LS;
- case op_copyb:
- return &list_1LS;
- case op_aload:
- case op_aloads:
- case op_aloadb:
- case op_aloadbit:
- return &list_LLS;
- case op_astore:
- case op_astores:
- case op_astoreb:
- case op_astorebit:
- return &list_LLL;
-
- case op_stkcount:
- return &list_S;
- case op_stkpeek:
- return &list_LS;
- case op_stkswap:
- return &list_none;
- case op_stkroll:
- return &list_LL;
- case op_stkcopy:
- return &list_L;
-
- case op_streamchar:
- case op_streamunichar:
- case op_streamnum:
- case op_streamstr:
- return &list_L;
- case op_getstringtbl:
- return &list_S;
- case op_setstringtbl:
- return &list_L;
- case op_getiosys:
- return &list_SS;
- case op_setiosys:
- return &list_LL;
-
- case op_random:
- return &list_LS;
- case op_setrandom:
- return &list_L;
-
- case op_verify:
- return &list_S;
- case op_restart:
- return &list_none;
- case op_save:
- case op_restore:
- return &list_LS;
- case op_saveundo:
- case op_restoreundo:
- return &list_S;
- case op_protect:
- return &list_LL;
-
- case op_quit:
- return &list_none;
-
- case op_gestalt:
- return &list_LLS;
-
- case op_debugtrap:
- return &list_L;
-
- case op_getmemsize:
- return &list_S;
- case op_setmemsize:
- return &list_LS;
-
- case op_linearsearch:
- return &list_LLLLLLLS;
- case op_binarysearch:
- return &list_LLLLLLLS;
- case op_linkedsearch:
- return &list_LLLLLLS;
-
- case op_glk:
- return &list_LLS;
-
- case op_callf:
- return &list_LS;
- case op_callfi:
- return &list_LLS;
- case op_callfii:
- return &list_LLLS;
- case op_callfiii:
- return &list_LLLLS;
-
- case op_mzero:
- return &list_LL;
- case op_mcopy:
- return &list_LLL;
- case op_malloc:
- return &list_LS;
- case op_mfree:
- return &list_L;
-
- case op_accelfunc:
- case op_accelparam:
- return &list_LL;
+ switch (opcode) {
+ case op_nop:
+ return &list_none;
+
+ case op_add:
+ case op_sub:
+ case op_mul:
+ case op_div:
+ case op_mod:
+ case op_bitand:
+ case op_bitor:
+ case op_bitxor:
+ case op_shiftl:
+ case op_sshiftr:
+ case op_ushiftr:
+ return &list_LLS;
+
+ case op_neg:
+ case op_bitnot:
+ return &list_LS;
+
+ case op_jump:
+ case op_jumpabs:
+ return &list_L;
+ case op_jz:
+ case op_jnz:
+ return &list_LL;
+ case op_jeq:
+ case op_jne:
+ case op_jlt:
+ case op_jge:
+ case op_jgt:
+ case op_jle:
+ case op_jltu:
+ case op_jgeu:
+ case op_jgtu:
+ case op_jleu:
+ return &list_LLL;
+
+ case op_call:
+ return &list_LLS;
+ case op_return:
+ return &list_L;
+ case op_catch:
+ return &list_SL;
+ case op_throw:
+ return &list_LL;
+ case op_tailcall:
+ return &list_LL;
+
+ case op_sexb:
+ case op_sexs:
+ return &list_LS;
+
+ case op_copy:
+ return &list_LS;
+ case op_copys:
+ return &list_2LS;
+ case op_copyb:
+ return &list_1LS;
+ case op_aload:
+ case op_aloads:
+ case op_aloadb:
+ case op_aloadbit:
+ return &list_LLS;
+ case op_astore:
+ case op_astores:
+ case op_astoreb:
+ case op_astorebit:
+ return &list_LLL;
+
+ case op_stkcount:
+ return &list_S;
+ case op_stkpeek:
+ return &list_LS;
+ case op_stkswap:
+ return &list_none;
+ case op_stkroll:
+ return &list_LL;
+ case op_stkcopy:
+ return &list_L;
+
+ case op_streamchar:
+ case op_streamunichar:
+ case op_streamnum:
+ case op_streamstr:
+ return &list_L;
+ case op_getstringtbl:
+ return &list_S;
+ case op_setstringtbl:
+ return &list_L;
+ case op_getiosys:
+ return &list_SS;
+ case op_setiosys:
+ return &list_LL;
+
+ case op_random:
+ return &list_LS;
+ case op_setrandom:
+ return &list_L;
+
+ case op_verify:
+ return &list_S;
+ case op_restart:
+ return &list_none;
+ case op_save:
+ case op_restore:
+ return &list_LS;
+ case op_saveundo:
+ case op_restoreundo:
+ return &list_S;
+ case op_protect:
+ return &list_LL;
+
+ case op_quit:
+ return &list_none;
+
+ case op_gestalt:
+ return &list_LLS;
+
+ case op_debugtrap:
+ return &list_L;
+
+ case op_getmemsize:
+ return &list_S;
+ case op_setmemsize:
+ return &list_LS;
+
+ case op_linearsearch:
+ return &list_LLLLLLLS;
+ case op_binarysearch:
+ return &list_LLLLLLLS;
+ case op_linkedsearch:
+ return &list_LLLLLLS;
+
+ case op_glk:
+ return &list_LLS;
+
+ case op_callf:
+ return &list_LS;
+ case op_callfi:
+ return &list_LLS;
+ case op_callfii:
+ return &list_LLLS;
+ case op_callfiii:
+ return &list_LLLLS;
+
+ case op_mzero:
+ return &list_LL;
+ case op_mcopy:
+ return &list_LLL;
+ case op_malloc:
+ return &list_LS;
+ case op_mfree:
+ return &list_L;
+
+ case op_accelfunc:
+ case op_accelparam:
+ return &list_LL;
#ifdef FLOAT_SUPPORT
- case op_numtof:
- case op_ftonumz:
- case op_ftonumn:
- case op_ceil:
- case op_floor:
- case op_sqrt:
- case op_exp:
- case op_log:
- return &list_LS;
- case op_fadd:
- case op_fsub:
- case op_fmul:
- case op_fdiv:
- case op_pow:
- case op_atan2:
- return &list_LLS;
- case op_fmod:
- return &list_LLSS;
- case op_sin:
- case op_cos:
- case op_tan:
- case op_asin:
- case op_acos:
- case op_atan:
- return &list_LS;
- case op_jfeq:
- case op_jfne:
- return &list_LLLL;
- case op_jflt:
- case op_jfle:
- case op_jfgt:
- case op_jfge:
- return &list_LLL;
- case op_jisnan:
- case op_jisinf:
- return &list_LL;
+ case op_numtof:
+ case op_ftonumz:
+ case op_ftonumn:
+ case op_ceil:
+ case op_floor:
+ case op_sqrt:
+ case op_exp:
+ case op_log:
+ return &list_LS;
+ case op_fadd:
+ case op_fsub:
+ case op_fmul:
+ case op_fdiv:
+ case op_pow:
+ case op_atan2:
+ return &list_LLS;
+ case op_fmod:
+ return &list_LLSS;
+ case op_sin:
+ case op_cos:
+ case op_tan:
+ case op_asin:
+ case op_acos:
+ case op_atan:
+ return &list_LS;
+ case op_jfeq:
+ case op_jfne:
+ return &list_LLLL;
+ case op_jflt:
+ case op_jfle:
+ case op_jfgt:
+ case op_jfge:
+ return &list_LLL;
+ case op_jisnan:
+ case op_jisinf:
+ return &list_LL;
#endif /* FLOAT_SUPPORT */
#ifdef GLULX_EXTEND_OPERANDS
- GLULX_EXTEND_OPERANDS
+ GLULX_EXTEND_OPERANDS
#endif /* GLULX_EXTEND_OPERANDS */
- default:
- return nullptr;
- }
+ default:
+ return nullptr;
+ }
}
void Glulxe::parse_operands(oparg_t *args, const operandlist_t *oplist) {
- int ix;
- oparg_t *curarg;
- int numops = oplist->num_ops;
- int argsize = oplist->arg_size;
- uint modeaddr = pc;
- int modeval = 0;
-
- pc += (numops+1) / 2;
-
- for (ix=0, curarg=args; ix<numops; ix++, curarg++) {
- int mode;
- uint value;
- uint addr;
-
- curarg->desttype = 0;
-
- if ((ix & 1) == 0) {
- modeval = Mem1(modeaddr);
- mode = (modeval & 0x0F);
- }
- else {
- mode = ((modeval >> 4) & 0x0F);
- modeaddr++;
- }
-
- if (oplist->formlist[ix] == modeform_Load) {
-
- switch (mode) {
-
- case 8: /* pop off stack */
- if (stackptr < valstackbase+4) {
- fatal_error("Stack underflow in operand.");
- }
- stackptr -= 4;
- value = Stk4(stackptr);
- break;
-
- case 0: /* constant zero */
- value = 0;
- break;
-
- case 1: /* one-byte constant */
- /* Sign-extend from 8 bits to 32 */
- value = (int)(signed char)(Mem1(pc));
- pc++;
- break;
-
- case 2: /* two-byte constant */
- /* Sign-extend the first byte from 8 bits to 32; the subsequent
- byte must not be sign-extended. */
- value = (int)(signed char)(Mem1(pc));
- pc++;
- value = (value << 8) | (uint)(Mem1(pc));
- pc++;
- break;
-
- case 3: /* four-byte constant */
- /* Bytes must not be sign-extended. */
- value = Mem4(pc);
- pc += 4;
- break;
-
- case 15: /* main memory RAM, four-byte address */
- addr = Mem4(pc);
- addr += ramstart;
- pc += 4;
- goto MainMemAddr;
-
- case 14: /* main memory RAM, two-byte address */
- addr = (uint)Mem2(pc);
- addr += ramstart;
- pc += 2;
- goto MainMemAddr;
-
- case 13: /* main memory RAM, one-byte address */
- addr = (uint)(Mem1(pc));
- addr += ramstart;
- pc++;
- goto MainMemAddr;
-
- case 7: /* main memory, four-byte address */
- addr = Mem4(pc);
- pc += 4;
- goto MainMemAddr;
-
- case 6: /* main memory, two-byte address */
- addr = (uint)Mem2(pc);
- pc += 2;
- goto MainMemAddr;
-
- case 5: /* main memory, one-byte address */
- addr = (uint)(Mem1(pc));
- pc++;
- /* fall through */
-
- MainMemAddr:
- /* cases 5, 6, 7, 13, 14, 15 all wind up here. */
- if (argsize == 4) {
- value = Mem4(addr);
- }
- else if (argsize == 2) {
- value = Mem2(addr);
- }
- else {
- value = Mem1(addr);
- }
- break;
-
- case 11: /* locals, four-byte address */
- addr = Mem4(pc);
- pc += 4;
- goto LocalsAddr;
-
- case 10: /* locals, two-byte address */
- addr = (uint)Mem2(pc);
- pc += 2;
- goto LocalsAddr;
-
- case 9: /* locals, one-byte address */
- addr = (uint)(Mem1(pc));
- pc++;
- /* fall through */
-
- LocalsAddr:
- /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
- be four-byte aligned, but we don't check this explicitly.
- A "strict mode" interpreter probably should. It's also illegal
- for addr to be less than zero or greater than the size of
- the locals segment. */
- addr += localsbase;
- if (argsize == 4) {
- value = Stk4(addr);
- }
- else if (argsize == 2) {
- value = Stk2(addr);
- }
- else {
- value = Stk1(addr);
- }
- break;
-
- default:
- value = 0;
- fatal_error("Unknown addressing mode in load operand.");
- }
-
- curarg->value = value;
-
- }
- else { /* modeform_Store */
- switch (mode) {
-
- case 0: /* discard value */
- curarg->desttype = 0;
- curarg->value = 0;
- break;
-
- case 8: /* push on stack */
- curarg->desttype = 3;
- curarg->value = 0;
- break;
-
- case 15: /* main memory RAM, four-byte address */
- addr = Mem4(pc);
- addr += ramstart;
- pc += 4;
- goto WrMainMemAddr;
-
- case 14: /* main memory RAM, two-byte address */
- addr = (uint)Mem2(pc);
- addr += ramstart;
- pc += 2;
- goto WrMainMemAddr;
-
- case 13: /* main memory RAM, one-byte address */
- addr = (uint)(Mem1(pc));
- addr += ramstart;
- pc++;
- goto WrMainMemAddr;
-
- case 7: /* main memory, four-byte address */
- addr = Mem4(pc);
- pc += 4;
- goto WrMainMemAddr;
-
- case 6: /* main memory, two-byte address */
- addr = (uint)Mem2(pc);
- pc += 2;
- goto WrMainMemAddr;
-
- case 5: /* main memory, one-byte address */
- addr = (uint)(Mem1(pc));
- pc++;
- /* fall through */
-
- WrMainMemAddr:
- /* cases 5, 6, 7 all wind up here. */
- curarg->desttype = 1;
- curarg->value = addr;
- break;
-
- case 11: /* locals, four-byte address */
- addr = Mem4(pc);
- pc += 4;
- goto WrLocalsAddr;
-
- case 10: /* locals, two-byte address */
- addr = (uint)Mem2(pc);
- pc += 2;
- goto WrLocalsAddr;
-
- case 9: /* locals, one-byte address */
- addr = (uint)(Mem1(pc));
- pc++;
- /* fall through */
-
- WrLocalsAddr:
- /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
- be four-byte aligned, but we don't check this explicitly.
- A "strict mode" interpreter probably should. It's also illegal
- for addr to be less than zero or greater than the size of
- the locals segment. */
- curarg->desttype = 2;
- /* We don't add localsbase here; the store address for desttype 2
- is relative to the current locals segment, not an absolute
- stack position. */
- curarg->value = addr;
- break;
-
- case 1:
- case 2:
- case 3:
- fatal_error("Constant addressing mode in store operand.");
-
- default:
- fatal_error("Unknown addressing mode in store operand.");
- }
- }
- }
+ int ix;
+ oparg_t *curarg;
+ int numops = oplist->num_ops;
+ int argsize = oplist->arg_size;
+ uint modeaddr = pc;
+ int modeval = 0;
+
+ pc += (numops + 1) / 2;
+
+ for (ix = 0, curarg = args; ix < numops; ix++, curarg++) {
+ int mode;
+ uint value;
+ uint addr;
+
+ curarg->desttype = 0;
+
+ if ((ix & 1) == 0) {
+ modeval = Mem1(modeaddr);
+ mode = (modeval & 0x0F);
+ } else {
+ mode = ((modeval >> 4) & 0x0F);
+ modeaddr++;
+ }
+
+ if (oplist->formlist[ix] == modeform_Load) {
+
+ switch (mode) {
+
+ case 8: /* pop off stack */
+ if (stackptr < valstackbase + 4) {
+ fatal_error("Stack underflow in operand.");
+ }
+ stackptr -= 4;
+ value = Stk4(stackptr);
+ break;
+
+ case 0: /* constant zero */
+ value = 0;
+ break;
+
+ case 1: /* one-byte constant */
+ /* Sign-extend from 8 bits to 32 */
+ value = (int)(signed char)(Mem1(pc));
+ pc++;
+ break;
+
+ case 2: /* two-byte constant */
+ /* Sign-extend the first byte from 8 bits to 32; the subsequent
+ byte must not be sign-extended. */
+ value = (int)(signed char)(Mem1(pc));
+ pc++;
+ value = (value << 8) | (uint)(Mem1(pc));
+ pc++;
+ break;
+
+ case 3: /* four-byte constant */
+ /* Bytes must not be sign-extended. */
+ value = Mem4(pc);
+ pc += 4;
+ break;
+
+ case 15: /* main memory RAM, four-byte address */
+ addr = Mem4(pc);
+ addr += ramstart;
+ pc += 4;
+ goto MainMemAddr;
+
+ case 14: /* main memory RAM, two-byte address */
+ addr = (uint)Mem2(pc);
+ addr += ramstart;
+ pc += 2;
+ goto MainMemAddr;
+
+ case 13: /* main memory RAM, one-byte address */
+ addr = (uint)(Mem1(pc));
+ addr += ramstart;
+ pc++;
+ goto MainMemAddr;
+
+ case 7: /* main memory, four-byte address */
+ addr = Mem4(pc);
+ pc += 4;
+ goto MainMemAddr;
+
+ case 6: /* main memory, two-byte address */
+ addr = (uint)Mem2(pc);
+ pc += 2;
+ goto MainMemAddr;
+
+ case 5: /* main memory, one-byte address */
+ addr = (uint)(Mem1(pc));
+ pc++;
+ /* fall through */
+
+MainMemAddr:
+ /* cases 5, 6, 7, 13, 14, 15 all wind up here. */
+ if (argsize == 4) {
+ value = Mem4(addr);
+ } else if (argsize == 2) {
+ value = Mem2(addr);
+ } else {
+ value = Mem1(addr);
+ }
+ break;
+
+ case 11: /* locals, four-byte address */
+ addr = Mem4(pc);
+ pc += 4;
+ goto LocalsAddr;
+
+ case 10: /* locals, two-byte address */
+ addr = (uint)Mem2(pc);
+ pc += 2;
+ goto LocalsAddr;
+
+ case 9: /* locals, one-byte address */
+ addr = (uint)(Mem1(pc));
+ pc++;
+ /* fall through */
+
+LocalsAddr:
+ /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
+ be four-byte aligned, but we don't check this explicitly.
+ A "strict mode" interpreter probably should. It's also illegal
+ for addr to be less than zero or greater than the size of
+ the locals segment. */
+ addr += localsbase;
+ if (argsize == 4) {
+ value = Stk4(addr);
+ } else if (argsize == 2) {
+ value = Stk2(addr);
+ } else {
+ value = Stk1(addr);
+ }
+ break;
+
+ default:
+ value = 0;
+ fatal_error("Unknown addressing mode in load operand.");
+ }
+
+ curarg->value = value;
+
+ } else { /* modeform_Store */
+ switch (mode) {
+
+ case 0: /* discard value */
+ curarg->desttype = 0;
+ curarg->value = 0;
+ break;
+
+ case 8: /* push on stack */
+ curarg->desttype = 3;
+ curarg->value = 0;
+ break;
+
+ case 15: /* main memory RAM, four-byte address */
+ addr = Mem4(pc);
+ addr += ramstart;
+ pc += 4;
+ goto WrMainMemAddr;
+
+ case 14: /* main memory RAM, two-byte address */
+ addr = (uint)Mem2(pc);
+ addr += ramstart;
+ pc += 2;
+ goto WrMainMemAddr;
+
+ case 13: /* main memory RAM, one-byte address */
+ addr = (uint)(Mem1(pc));
+ addr += ramstart;
+ pc++;
+ goto WrMainMemAddr;
+
+ case 7: /* main memory, four-byte address */
+ addr = Mem4(pc);
+ pc += 4;
+ goto WrMainMemAddr;
+
+ case 6: /* main memory, two-byte address */
+ addr = (uint)Mem2(pc);
+ pc += 2;
+ goto WrMainMemAddr;
+
+ case 5: /* main memory, one-byte address */
+ addr = (uint)(Mem1(pc));
+ pc++;
+ /* fall through */
+
+WrMainMemAddr:
+ /* cases 5, 6, 7 all wind up here. */
+ curarg->desttype = 1;
+ curarg->value = addr;
+ break;
+
+ case 11: /* locals, four-byte address */
+ addr = Mem4(pc);
+ pc += 4;
+ goto WrLocalsAddr;
+
+ case 10: /* locals, two-byte address */
+ addr = (uint)Mem2(pc);
+ pc += 2;
+ goto WrLocalsAddr;
+
+ case 9: /* locals, one-byte address */
+ addr = (uint)(Mem1(pc));
+ pc++;
+ /* fall through */
+
+WrLocalsAddr:
+ /* cases 9, 10, 11 all wind up here. It's illegal for addr to not
+ be four-byte aligned, but we don't check this explicitly.
+ A "strict mode" interpreter probably should. It's also illegal
+ for addr to be less than zero or greater than the size of
+ the locals segment. */
+ curarg->desttype = 2;
+ /* We don't add localsbase here; the store address for desttype 2
+ is relative to the current locals segment, not an absolute
+ stack position. */
+ curarg->value = addr;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ fatal_error("Constant addressing mode in store operand.");
+
+ default:
+ fatal_error("Unknown addressing mode in store operand.");
+ }
+ }
+ }
}
void Glulxe::store_operand(uint desttype, uint destaddr, uint storeval) {
- switch (desttype) {
+ switch (desttype) {
- case 0: /* do nothing; discard the value. */
- return;
+ case 0: /* do nothing; discard the value. */
+ return;
- case 1: /* main memory. */
- MemW4(destaddr, storeval);
- return;
+ case 1: /* main memory. */
+ MemW4(destaddr, storeval);
+ return;
- case 2: /* locals. */
- destaddr += localsbase;
- StkW4(destaddr, storeval);
- return;
+ case 2: /* locals. */
+ destaddr += localsbase;
+ StkW4(destaddr, storeval);
+ return;
- case 3: /* push on stack. */
- if (stackptr+4 > stacksize) {
- fatal_error("Stack overflow in store operand.");
- }
- StkW4(stackptr, storeval);
- stackptr += 4;
- return;
+ case 3: /* push on stack. */
+ if (stackptr + 4 > stacksize) {
+ fatal_error("Stack overflow in store operand.");
+ }
+ StkW4(stackptr, storeval);
+ stackptr += 4;
+ return;
- default:
- fatal_error("Unknown destination type in store operand.");
+ default:
+ fatal_error("Unknown destination type in store operand.");
- }
+ }
}
void Glulxe::store_operand_s(uint desttype, uint destaddr, uint storeval) {
- storeval &= 0xFFFF;
+ storeval &= 0xFFFF;
- switch (desttype) {
+ switch (desttype) {
- case 0: /* do nothing; discard the value. */
- return;
+ case 0: /* do nothing; discard the value. */
+ return;
- case 1: /* main memory. */
- MemW2(destaddr, storeval);
- return;
+ case 1: /* main memory. */
+ MemW2(destaddr, storeval);
+ return;
- case 2: /* locals. */
- destaddr += localsbase;
- StkW2(destaddr, storeval);
- return;
+ case 2: /* locals. */
+ destaddr += localsbase;
+ StkW2(destaddr, storeval);
+ return;
- case 3: /* push on stack. A four-byte value is actually pushed. */
- if (stackptr+4 > stacksize) {
- fatal_error("Stack overflow in store operand.");
- }
- StkW4(stackptr, storeval);
- stackptr += 4;
- return;
+ case 3: /* push on stack. A four-byte value is actually pushed. */
+ if (stackptr + 4 > stacksize) {
+ fatal_error("Stack overflow in store operand.");
+ }
+ StkW4(stackptr, storeval);
+ stackptr += 4;
+ return;
- default:
- fatal_error("Unknown destination type in store operand.");
+ default:
+ fatal_error("Unknown destination type in store operand.");
- }
+ }
}
void Glulxe::store_operand_b(uint desttype, uint destaddr, uint storeval) {
- storeval &= 0xFF;
+ storeval &= 0xFF;
- switch (desttype) {
+ switch (desttype) {
- case 0: /* do nothing; discard the value. */
- return;
+ case 0: /* do nothing; discard the value. */
+ return;
- case 1: /* main memory. */
- MemW1(destaddr, storeval);
- return;
+ case 1: /* main memory. */
+ MemW1(destaddr, storeval);
+ return;
- case 2: /* locals. */
- destaddr += localsbase;
- StkW1(destaddr, storeval);
- return;
+ case 2: /* locals. */
+ destaddr += localsbase;
+ StkW1(destaddr, storeval);
+ return;
- case 3: /* push on stack. A four-byte value is actually pushed. */
- if (stackptr+4 > stacksize) {
- fatal_error("Stack overflow in store operand.");
- }
- StkW4(stackptr, storeval);
- stackptr += 4;
- return;
+ case 3: /* push on stack. A four-byte value is actually pushed. */
+ if (stackptr + 4 > stacksize) {
+ fatal_error("Stack overflow in store operand.");
+ }
+ StkW4(stackptr, storeval);
+ stackptr += 4;
+ return;
- default:
- fatal_error("Unknown destination type in store operand.");
+ default:
+ fatal_error("Unknown destination type in store operand.");
- }
+ }
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/search.cpp b/engines/glk/glulxe/search.cpp
index 440da553f0..1bbe8fa027 100644
--- a/engines/glk/glulxe/search.cpp
+++ b/engines/glk/glulxe/search.cpp
@@ -31,185 +31,180 @@ enum serop {
serop_ReturnIndex = 0x04
};
-uint Glulxe::linear_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
- uint keyoffset, uint options) {
- unsigned char keybuf[4];
- uint count;
- uint ix;
- int retindex = ((options & serop_ReturnIndex) != 0);
- int zeroterm = ((options & serop_ZeroKeyTerminates) != 0);
-
- fetchkey(keybuf, key, keysize, options);
-
- for (count=0; count<numstructs; count++, start+=structsize) {
- int match = true;
- if (keysize <= 4) {
- for (ix=0; match && ix<keysize; ix++) {
- if (Mem1(start + keyoffset + ix) != keybuf[ix])
- match = false;
- }
- }
- else {
- for (ix=0; match && ix<keysize; ix++) {
- if (Mem1(start + keyoffset + ix) != Mem1(key + ix))
- match = false;
- }
- }
-
- if (match) {
- if (retindex)
- return count;
- else
- return start;
- }
-
- if (zeroterm) {
- match = true;
- for (ix=0; match && ix<keysize; ix++) {
- if (Mem1(start + keyoffset + ix) != 0)
- match = false;
- }
- if (match) {
- break;
- }
- }
- }
-
- if (retindex)
- return (uint)-1;
- else
- return 0;
+uint Glulxe::linear_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
+ uint keyoffset, uint options) {
+ unsigned char keybuf[4];
+ uint count;
+ uint ix;
+ int retindex = ((options & serop_ReturnIndex) != 0);
+ int zeroterm = ((options & serop_ZeroKeyTerminates) != 0);
+
+ fetchkey(keybuf, key, keysize, options);
+
+ for (count = 0; count < numstructs; count++, start += structsize) {
+ int match = true;
+ if (keysize <= 4) {
+ for (ix = 0; match && ix < keysize; ix++) {
+ if (Mem1(start + keyoffset + ix) != keybuf[ix])
+ match = false;
+ }
+ } else {
+ for (ix = 0; match && ix < keysize; ix++) {
+ if (Mem1(start + keyoffset + ix) != Mem1(key + ix))
+ match = false;
+ }
+ }
+
+ if (match) {
+ if (retindex)
+ return count;
+ else
+ return start;
+ }
+
+ if (zeroterm) {
+ match = true;
+ for (ix = 0; match && ix < keysize; ix++) {
+ if (Mem1(start + keyoffset + ix) != 0)
+ match = false;
+ }
+ if (match) {
+ break;
+ }
+ }
+ }
+
+ if (retindex)
+ return (uint) - 1;
+ else
+ return 0;
}
-uint Glulxe::binary_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
- uint keyoffset, uint options) {
- byte keybuf[4];
- byte byte1, byte2;
- uint top, bot, val, addr;
- uint ix;
- int retindex = ((options & serop_ReturnIndex) != 0);
-
- fetchkey(keybuf, key, keysize, options);
-
- bot = 0;
- top = numstructs;
- while (bot < top) {
- int cmp = 0;
- val = (top+bot) / 2;
- addr = start + val * structsize;
-
- if (keysize <= 4) {
- for (ix=0; (!cmp) && ix<keysize; ix++) {
- byte1 = Mem1(addr + keyoffset + ix);
- byte2 = keybuf[ix];
- if (byte1 < byte2)
- cmp = -1;
- else if (byte1 > byte2)
- cmp = 1;
- }
- }
- else {
- for (ix=0; (!cmp) && ix<keysize; ix++) {
- byte1 = Mem1(addr + keyoffset + ix);
- byte2 = Mem1(key + ix);
- if (byte1 < byte2)
- cmp = -1;
- else if (byte1 > byte2)
- cmp = 1;
- }
- }
-
- if (!cmp) {
- if (retindex)
- return val;
- else
- return addr;
- }
-
- if (cmp < 0) {
- bot = val+1;
- }
- else {
- top = val;
- }
- }
-
- if (retindex)
- return (uint)-1;
- else
- return 0;
+uint Glulxe::binary_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
+ uint keyoffset, uint options) {
+ byte keybuf[4];
+ byte byte1, byte2;
+ uint top, bot, val, addr;
+ uint ix;
+ int retindex = ((options & serop_ReturnIndex) != 0);
+
+ fetchkey(keybuf, key, keysize, options);
+
+ bot = 0;
+ top = numstructs;
+ while (bot < top) {
+ int cmp = 0;
+ val = (top + bot) / 2;
+ addr = start + val * structsize;
+
+ if (keysize <= 4) {
+ for (ix = 0; (!cmp) && ix < keysize; ix++) {
+ byte1 = Mem1(addr + keyoffset + ix);
+ byte2 = keybuf[ix];
+ if (byte1 < byte2)
+ cmp = -1;
+ else if (byte1 > byte2)
+ cmp = 1;
+ }
+ } else {
+ for (ix = 0; (!cmp) && ix < keysize; ix++) {
+ byte1 = Mem1(addr + keyoffset + ix);
+ byte2 = Mem1(key + ix);
+ if (byte1 < byte2)
+ cmp = -1;
+ else if (byte1 > byte2)
+ cmp = 1;
+ }
+ }
+
+ if (!cmp) {
+ if (retindex)
+ return val;
+ else
+ return addr;
+ }
+
+ if (cmp < 0) {
+ bot = val + 1;
+ } else {
+ top = val;
+ }
+ }
+
+ if (retindex)
+ return (uint) - 1;
+ else
+ return 0;
}
uint Glulxe::linked_search(uint key, uint keysize, uint start, uint keyoffset, uint nextoffset, uint options) {
- unsigned char keybuf[4];
- uint ix;
- uint val;
- int zeroterm = ((options & serop_ZeroKeyTerminates) != 0);
-
- fetchkey(keybuf, key, keysize, options);
-
- while (start != 0) {
- int match = true;
- if (keysize <= 4) {
- for (ix=0; match && ix<keysize; ix++) {
- if (Mem1(start + keyoffset + ix) != keybuf[ix])
- match = false;
- }
- }
- else {
- for (ix=0; match && ix<keysize; ix++) {
- if (Mem1(start + keyoffset + ix) != Mem1(key + ix))
- match = false;
- }
- }
-
- if (match) {
- return start;
- }
-
- if (zeroterm) {
- match = true;
- for (ix=0; match && ix<keysize; ix++) {
- if (Mem1(start + keyoffset + ix) != 0)
- match = false;
- }
- if (match) {
- break;
- }
- }
-
- val = start + nextoffset;
- start = Mem4(val);
- }
-
- return 0;
+ unsigned char keybuf[4];
+ uint ix;
+ uint val;
+ int zeroterm = ((options & serop_ZeroKeyTerminates) != 0);
+
+ fetchkey(keybuf, key, keysize, options);
+
+ while (start != 0) {
+ int match = true;
+ if (keysize <= 4) {
+ for (ix = 0; match && ix < keysize; ix++) {
+ if (Mem1(start + keyoffset + ix) != keybuf[ix])
+ match = false;
+ }
+ } else {
+ for (ix = 0; match && ix < keysize; ix++) {
+ if (Mem1(start + keyoffset + ix) != Mem1(key + ix))
+ match = false;
+ }
+ }
+
+ if (match) {
+ return start;
+ }
+
+ if (zeroterm) {
+ match = true;
+ for (ix = 0; match && ix < keysize; ix++) {
+ if (Mem1(start + keyoffset + ix) != 0)
+ match = false;
+ }
+ if (match) {
+ break;
+ }
+ }
+
+ val = start + nextoffset;
+ start = Mem4(val);
+ }
+
+ return 0;
}
void Glulxe::fetchkey(unsigned char *keybuf, uint key, uint keysize, uint options) {
- uint ix;
-
- if (options & serop_KeyIndirect) {
- if (keysize <= 4) {
- for (ix=0; ix<keysize; ix++)
- keybuf[ix] = Mem1(key+ix);
- }
- }
- else {
- switch (keysize) {
- case 4:
- Write4(keybuf, key);
- break;
- case 2:
- Write2(keybuf, key);
- break;
- case 1:
- Write1(keybuf, key);
- break;
- default:
- fatal_error("Direct search key must hold one, two, or four bytes.");
- }
- }
+ uint ix;
+
+ if (options & serop_KeyIndirect) {
+ if (keysize <= 4) {
+ for (ix = 0; ix < keysize; ix++)
+ keybuf[ix] = Mem1(key + ix);
+ }
+ } else {
+ switch (keysize) {
+ case 4:
+ Write4(keybuf, key);
+ break;
+ case 2:
+ Write2(keybuf, key);
+ break;
+ case 1:
+ Write1(keybuf, key);
+ break;
+ default:
+ fatal_error("Direct search key must hold one, two, or four bytes.");
+ }
+ }
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/serial.cpp b/engines/glk/glulxe/serial.cpp
index bc267884b5..01848fc8cd 100644
--- a/engines/glk/glulxe/serial.cpp
+++ b/engines/glk/glulxe/serial.cpp
@@ -28,1116 +28,1104 @@ namespace Glulxe {
#define IFFID(c1, c2, c3, c4) MKTAG(c1, c2, c3, c4)
bool Glulxe::init_serial() {
- undo_chain_num = 0;
- undo_chain_size = max_undo_level;
- undo_chain = (unsigned char **)glulx_malloc(sizeof(unsigned char *) * undo_chain_size);
- if (!undo_chain)
- return false;
+ undo_chain_num = 0;
+ undo_chain_size = max_undo_level;
+ undo_chain = (unsigned char **)glulx_malloc(sizeof(unsigned char *) * undo_chain_size);
+ if (!undo_chain)
+ return false;
#ifdef SERIALIZE_CACHE_RAM
- {
- uint len = (endmem - ramstart);
- uint res;
- ramcache = (unsigned char *)glulx_malloc(sizeof(unsigned char *) * len);
- if (!ramcache)
- return false;
-
- _gameFile.seek(gamefile_start + ramstart);
- res = _gameFile.read(ramcache, len);
- if (res != len)
- return false;
- }
+ {
+ uint len = (endmem - ramstart);
+ uint res;
+ ramcache = (unsigned char *)glulx_malloc(sizeof(unsigned char *) * len);
+ if (!ramcache)
+ return false;
+
+ _gameFile.seek(gamefile_start + ramstart);
+ res = _gameFile.read(ramcache, len);
+ if (res != len)
+ return false;
+ }
#endif /* SERIALIZE_CACHE_RAM */
- return true;
+ return true;
}
void Glulxe::final_serial() {
- if (undo_chain) {
- int ix;
- for (ix=0; ix<undo_chain_num; ix++) {
- glulx_free(undo_chain[ix]);
- }
- glulx_free(undo_chain);
- }
- undo_chain = nullptr;
- undo_chain_size = 0;
- undo_chain_num = 0;
+ if (undo_chain) {
+ int ix;
+ for (ix = 0; ix < undo_chain_num; ix++) {
+ glulx_free(undo_chain[ix]);
+ }
+ glulx_free(undo_chain);
+ }
+ undo_chain = nullptr;
+ undo_chain_size = 0;
+ undo_chain_num = 0;
#ifdef SERIALIZE_CACHE_RAM
- if (ramcache) {
- glulx_free(ramcache);
- ramcache = nullptr;
- }
+ if (ramcache) {
+ glulx_free(ramcache);
+ ramcache = nullptr;
+ }
#endif /* SERIALIZE_CACHE_RAM */
}
uint Glulxe::perform_saveundo() {
- dest_t dest;
- uint res;
- uint memstart = 0, memlen = 0, heapstart = 0, heaplen = 0;
- uint stackstart = 0, stacklen = 0;
-
- /* The format for undo-saves is simpler than for saves on disk. We
- just have a memory chunk, a heap chunk, and a stack chunk, in
- that order. We skip the IFF chunk headers (although the size
- fields are still there.) We also don't bother with IFF's 16-bit
- alignment. */
-
- if (undo_chain_size == 0)
- return 1;
-
- dest.ismem = true;
- dest.size = 0;
- dest.pos = 0;
- dest.ptr = nullptr;
- dest.str = nullptr;
-
- res = 0;
- if (res == 0) {
- res = write_long(&dest, 0); /* space for chunk length */
- }
- if (res == 0) {
- memstart = dest.pos;
- res = write_memstate(&dest);
- memlen = dest.pos - memstart;
- }
- if (res == 0) {
- res = write_long(&dest, 0); /* space for chunk length */
- }
- if (res == 0) {
- heapstart = dest.pos;
- res = write_heapstate(&dest, false);
- heaplen = dest.pos - heapstart;
- }
- if (res == 0) {
- res = write_long(&dest, 0); /* space for chunk length */
- }
- if (res == 0) {
- stackstart = dest.pos;
- res = write_stackstate(&dest, false);
- stacklen = dest.pos - stackstart;
- }
-
- if (res == 0) {
- /* Trim it down to the perfect size. */
- dest.ptr = (byte *)glulx_realloc(dest.ptr, dest.pos);
- if (!dest.ptr)
- res = 1;
- }
- if (res == 0) {
- res = reposition_write(&dest, memstart-4);
- }
- if (res == 0) {
- res = write_long(&dest, memlen);
- }
- if (res == 0) {
- res = reposition_write(&dest, heapstart-4);
- }
- if (res == 0) {
- res = write_long(&dest, heaplen);
- }
- if (res == 0) {
- res = reposition_write(&dest, stackstart-4);
- }
- if (res == 0) {
- res = write_long(&dest, stacklen);
- }
-
- if (res == 0) {
- /* It worked. */
- if (undo_chain_num >= undo_chain_size) {
- glulx_free(undo_chain[undo_chain_num-1]);
- undo_chain[undo_chain_num-1] = nullptr;
- }
- if (undo_chain_size > 1)
- memmove(undo_chain+1, undo_chain,
- (undo_chain_size-1) * sizeof(unsigned char *));
- undo_chain[0] = dest.ptr;
- if (undo_chain_num < undo_chain_size)
- undo_chain_num += 1;
- dest.ptr = nullptr;
- }
- else {
- /* It didn't work. */
- if (dest.ptr) {
- glulx_free(dest.ptr);
- dest.ptr = nullptr;
- }
- }
-
- return res;
+ dest_t dest;
+ uint res;
+ uint memstart = 0, memlen = 0, heapstart = 0, heaplen = 0;
+ uint stackstart = 0, stacklen = 0;
+
+ /* The format for undo-saves is simpler than for saves on disk. We
+ just have a memory chunk, a heap chunk, and a stack chunk, in
+ that order. We skip the IFF chunk headers (although the size
+ fields are still there.) We also don't bother with IFF's 16-bit
+ alignment. */
+
+ if (undo_chain_size == 0)
+ return 1;
+
+ dest.ismem = true;
+ dest.size = 0;
+ dest.pos = 0;
+ dest.ptr = nullptr;
+ dest.str = nullptr;
+
+ res = 0;
+ if (res == 0) {
+ res = write_long(&dest, 0); /* space for chunk length */
+ }
+ if (res == 0) {
+ memstart = dest.pos;
+ res = write_memstate(&dest);
+ memlen = dest.pos - memstart;
+ }
+ if (res == 0) {
+ res = write_long(&dest, 0); /* space for chunk length */
+ }
+ if (res == 0) {
+ heapstart = dest.pos;
+ res = write_heapstate(&dest, false);
+ heaplen = dest.pos - heapstart;
+ }
+ if (res == 0) {
+ res = write_long(&dest, 0); /* space for chunk length */
+ }
+ if (res == 0) {
+ stackstart = dest.pos;
+ res = write_stackstate(&dest, false);
+ stacklen = dest.pos - stackstart;
+ }
+
+ if (res == 0) {
+ /* Trim it down to the perfect size. */
+ dest.ptr = (byte *)glulx_realloc(dest.ptr, dest.pos);
+ if (!dest.ptr)
+ res = 1;
+ }
+ if (res == 0) {
+ res = reposition_write(&dest, memstart - 4);
+ }
+ if (res == 0) {
+ res = write_long(&dest, memlen);
+ }
+ if (res == 0) {
+ res = reposition_write(&dest, heapstart - 4);
+ }
+ if (res == 0) {
+ res = write_long(&dest, heaplen);
+ }
+ if (res == 0) {
+ res = reposition_write(&dest, stackstart - 4);
+ }
+ if (res == 0) {
+ res = write_long(&dest, stacklen);
+ }
+
+ if (res == 0) {
+ /* It worked. */
+ if (undo_chain_num >= undo_chain_size) {
+ glulx_free(undo_chain[undo_chain_num - 1]);
+ undo_chain[undo_chain_num - 1] = nullptr;
+ }
+ if (undo_chain_size > 1)
+ memmove(undo_chain + 1, undo_chain,
+ (undo_chain_size - 1) * sizeof(unsigned char *));
+ undo_chain[0] = dest.ptr;
+ if (undo_chain_num < undo_chain_size)
+ undo_chain_num += 1;
+ dest.ptr = nullptr;
+ } else {
+ /* It didn't work. */
+ if (dest.ptr) {
+ glulx_free(dest.ptr);
+ dest.ptr = nullptr;
+ }
+ }
+
+ return res;
}
uint Glulxe::perform_restoreundo() {
- dest_t dest;
- uint res, val = 0;
- uint heapsumlen = 0;
- uint *heapsumarr = nullptr;
-
- /* If profiling is enabled and active then fail. */
- #if VM_PROFILING
- if (profile_profiling_active())
- return 1;
- #endif /* VM_PROFILING */
-
- if (undo_chain_size == 0 || undo_chain_num == 0)
- return 1;
-
- dest.ismem = true;
- dest.size = 0;
- dest.pos = 0;
- dest.ptr = undo_chain[0];
- dest.str = nullptr;
-
- res = 0;
- if (res == 0) {
- res = read_long(&dest, &val);
- }
- if (res == 0) {
- res = read_memstate(&dest, val);
- }
- if (res == 0) {
- res = read_long(&dest, &val);
- }
- if (res == 0) {
- res = read_heapstate(&dest, val, false, &heapsumlen, &heapsumarr);
- }
- if (res == 0) {
- res = read_long(&dest, &val);
- }
- if (res == 0) {
- res = read_stackstate(&dest, val, false);
- }
- /* ### really, many of the failure modes of those calls ought to
- cause fatal errors. The stack or main memory may be damaged now. */
-
- if (res == 0) {
- if (heapsumarr)
- res = heap_apply_summary(heapsumlen, heapsumarr);
- }
-
- if (res == 0) {
- /* It worked. */
- if (undo_chain_size > 1)
- memmove(undo_chain, undo_chain+1,
- (undo_chain_size-1) * sizeof(unsigned char *));
- undo_chain_num -= 1;
- glulx_free(dest.ptr);
- dest.ptr = nullptr;
- }
- else {
- /* It didn't work. */
- dest.ptr = nullptr;
- }
-
- return res;
+ dest_t dest;
+ uint res, val = 0;
+ uint heapsumlen = 0;
+ uint *heapsumarr = nullptr;
+
+ /* If profiling is enabled and active then fail. */
+#if VM_PROFILING
+ if (profile_profiling_active())
+ return 1;
+#endif /* VM_PROFILING */
+
+ if (undo_chain_size == 0 || undo_chain_num == 0)
+ return 1;
+
+ dest.ismem = true;
+ dest.size = 0;
+ dest.pos = 0;
+ dest.ptr = undo_chain[0];
+ dest.str = nullptr;
+
+ res = 0;
+ if (res == 0) {
+ res = read_long(&dest, &val);
+ }
+ if (res == 0) {
+ res = read_memstate(&dest, val);
+ }
+ if (res == 0) {
+ res = read_long(&dest, &val);
+ }
+ if (res == 0) {
+ res = read_heapstate(&dest, val, false, &heapsumlen, &heapsumarr);
+ }
+ if (res == 0) {
+ res = read_long(&dest, &val);
+ }
+ if (res == 0) {
+ res = read_stackstate(&dest, val, false);
+ }
+ /* ### really, many of the failure modes of those calls ought to
+ cause fatal errors. The stack or main memory may be damaged now. */
+
+ if (res == 0) {
+ if (heapsumarr)
+ res = heap_apply_summary(heapsumlen, heapsumarr);
+ }
+
+ if (res == 0) {
+ /* It worked. */
+ if (undo_chain_size > 1)
+ memmove(undo_chain, undo_chain + 1,
+ (undo_chain_size - 1) * sizeof(unsigned char *));
+ undo_chain_num -= 1;
+ glulx_free(dest.ptr);
+ dest.ptr = nullptr;
+ } else {
+ /* It didn't work. */
+ dest.ptr = nullptr;
+ }
+
+ return res;
}
uint Glulxe::perform_save(strid_t str) {
- dest_t dest;
- int ix;
- uint res, lx, val;
- uint memstart = 0, memlen = 0, stackstart = 0, stacklen = 0;
- uint heapstart = 0, heaplen = 0, filestart = 0, filelen = 0;
-
- stream_get_iosys(&val, &lx);
- if (val != 2) {
- /* Not using the Glk I/O system, so bail. This function only
- knows how to write to a Glk stream. */
- fatal_error("Streams are only available in Glk I/O system.");
- }
-
- if (str == 0)
- return 1;
-
- dest.ismem = false;
- dest.size = 0;
- dest.pos = 0;
- dest.ptr = nullptr;
- dest.str = str;
-
- res = 0;
-
- /* Quetzal header. */
- if (res == 0) {
- res = write_long(&dest, IFFID('F', 'O', 'R', 'M'));
- }
- if (res == 0) {
- res = write_long(&dest, 0); /* space for file length */
- filestart = dest.pos;
- }
-
- if (res == 0) {
- res = write_long(&dest, IFFID('I', 'F', 'Z', 'S')); /* ### ? */
- }
-
- /* Header chunk. This is the first 128 bytes of memory. */
- if (res == 0) {
- res = write_long(&dest, IFFID('I', 'F', 'h', 'd'));
- }
- if (res == 0) {
- res = write_long(&dest, 128);
- }
- for (ix=0; res==0 && ix<128; ix++) {
- res = write_byte(&dest, Mem1(ix));
- }
- /* Always even, so no padding necessary. */
-
- /* Memory chunk. */
- if (res == 0) {
- res = write_long(&dest, IFFID('C', 'M', 'e', 'm'));
- }
- if (res == 0) {
- res = write_long(&dest, 0); /* space for chunk length */
- }
- if (res == 0) {
- memstart = dest.pos;
- res = write_memstate(&dest);
- memlen = dest.pos - memstart;
- }
- if (res == 0 && (memlen & 1) != 0) {
- res = write_byte(&dest, 0);
- }
-
- /* Heap chunk. */
- if (res == 0) {
- res = write_long(&dest, IFFID('M', 'A', 'l', 'l'));
- }
- if (res == 0) {
- res = write_long(&dest, 0); /* space for chunk length */
- }
- if (res == 0) {
- heapstart = dest.pos;
- res = write_heapstate(&dest, true);
- heaplen = dest.pos - heapstart;
- }
- /* Always even, so no padding necessary. */
-
- /* Stack chunk. */
- if (res == 0) {
- res = write_long(&dest, IFFID('S', 't', 'k', 's'));
- }
- if (res == 0) {
- res = write_long(&dest, 0); /* space for chunk length */
- }
- if (res == 0) {
- stackstart = dest.pos;
- res = write_stackstate(&dest, true);
- stacklen = dest.pos - stackstart;
- }
- if (res == 0 && (stacklen & 1) != 0) {
- res = write_byte(&dest, 0);
- }
-
- filelen = dest.pos - filestart;
-
- /* Okay, fill in all the lengths. */
- if (res == 0) {
- res = reposition_write(&dest, memstart-4);
- }
- if (res == 0) {
- res = write_long(&dest, memlen);
- }
- if (res == 0) {
- res = reposition_write(&dest, heapstart-4);
- }
- if (res == 0) {
- res = write_long(&dest, heaplen);
- }
- if (res == 0) {
- res = reposition_write(&dest, stackstart-4);
- }
- if (res == 0) {
- res = write_long(&dest, stacklen);
- }
- if (res == 0) {
- res = reposition_write(&dest, filestart-4);
- }
- if (res == 0) {
- res = write_long(&dest, filelen);
- }
-
- /* All done. */
-
- return res;
+ dest_t dest;
+ int ix;
+ uint res, lx, val;
+ uint memstart = 0, memlen = 0, stackstart = 0, stacklen = 0;
+ uint heapstart = 0, heaplen = 0, filestart = 0, filelen = 0;
+
+ stream_get_iosys(&val, &lx);
+ if (val != 2) {
+ /* Not using the Glk I/O system, so bail. This function only
+ knows how to write to a Glk stream. */
+ fatal_error("Streams are only available in Glk I/O system.");
+ }
+
+ if (str == 0)
+ return 1;
+
+ dest.ismem = false;
+ dest.size = 0;
+ dest.pos = 0;
+ dest.ptr = nullptr;
+ dest.str = str;
+
+ res = 0;
+
+ /* Quetzal header. */
+ if (res == 0) {
+ res = write_long(&dest, IFFID('F', 'O', 'R', 'M'));
+ }
+ if (res == 0) {
+ res = write_long(&dest, 0); /* space for file length */
+ filestart = dest.pos;
+ }
+
+ if (res == 0) {
+ res = write_long(&dest, IFFID('I', 'F', 'Z', 'S')); /* ### ? */
+ }
+
+ /* Header chunk. This is the first 128 bytes of memory. */
+ if (res == 0) {
+ res = write_long(&dest, IFFID('I', 'F', 'h', 'd'));
+ }
+ if (res == 0) {
+ res = write_long(&dest, 128);
+ }
+ for (ix = 0; res == 0 && ix < 128; ix++) {
+ res = write_byte(&dest, Mem1(ix));
+ }
+ /* Always even, so no padding necessary. */
+
+ /* Memory chunk. */
+ if (res == 0) {
+ res = write_long(&dest, IFFID('C', 'M', 'e', 'm'));
+ }
+ if (res == 0) {
+ res = write_long(&dest, 0); /* space for chunk length */
+ }
+ if (res == 0) {
+ memstart = dest.pos;
+ res = write_memstate(&dest);
+ memlen = dest.pos - memstart;
+ }
+ if (res == 0 && (memlen & 1) != 0) {
+ res = write_byte(&dest, 0);
+ }
+
+ /* Heap chunk. */
+ if (res == 0) {
+ res = write_long(&dest, IFFID('M', 'A', 'l', 'l'));
+ }
+ if (res == 0) {
+ res = write_long(&dest, 0); /* space for chunk length */
+ }
+ if (res == 0) {
+ heapstart = dest.pos;
+ res = write_heapstate(&dest, true);
+ heaplen = dest.pos - heapstart;
+ }
+ /* Always even, so no padding necessary. */
+
+ /* Stack chunk. */
+ if (res == 0) {
+ res = write_long(&dest, IFFID('S', 't', 'k', 's'));
+ }
+ if (res == 0) {
+ res = write_long(&dest, 0); /* space for chunk length */
+ }
+ if (res == 0) {
+ stackstart = dest.pos;
+ res = write_stackstate(&dest, true);
+ stacklen = dest.pos - stackstart;
+ }
+ if (res == 0 && (stacklen & 1) != 0) {
+ res = write_byte(&dest, 0);
+ }
+
+ filelen = dest.pos - filestart;
+
+ /* Okay, fill in all the lengths. */
+ if (res == 0) {
+ res = reposition_write(&dest, memstart - 4);
+ }
+ if (res == 0) {
+ res = write_long(&dest, memlen);
+ }
+ if (res == 0) {
+ res = reposition_write(&dest, heapstart - 4);
+ }
+ if (res == 0) {
+ res = write_long(&dest, heaplen);
+ }
+ if (res == 0) {
+ res = reposition_write(&dest, stackstart - 4);
+ }
+ if (res == 0) {
+ res = write_long(&dest, stacklen);
+ }
+ if (res == 0) {
+ res = reposition_write(&dest, filestart - 4);
+ }
+ if (res == 0) {
+ res = write_long(&dest, filelen);
+ }
+
+ /* All done. */
+
+ return res;
}
uint Glulxe::perform_restore(strid_t str, int fromshell) {
- dest_t dest;
- int ix;
- uint lx, res, val;
- uint filestart, filelen = 0;
- uint heapsumlen = 0;
- uint *heapsumarr = nullptr;
-
- /* If profiling is enabled and active then fail. */
- #if VM_PROFILING
- if (profile_profiling_active())
- return 1;
- #endif /* VM_PROFILING */
-
- stream_get_iosys(&val, &lx);
- if (val != 2 && !fromshell) {
- /* Not using the Glk I/O system, so bail. This function only
- knows how to read from a Glk stream. (But in the autorestore
- case, iosys hasn't been set yet, so ignore this test.) */
- fatal_error("Streams are only available in Glk I/O system.");
- }
-
- if (str == 0)
- return 1;
-
- dest.ismem = false;
- dest.size = 0;
- dest.pos = 0;
- dest.ptr = nullptr;
- dest.str = str;
-
- res = 0;
-
- /* ### the format errors checked below should send error messages to
- the current stream. */
-
- if (res == 0) {
- res = read_long(&dest, &val);
- }
- if (res == 0 && val != IFFID('F', 'O', 'R', 'M')) {
- /* ### bad header */
- return 1;
- }
- if (res == 0) {
- res = read_long(&dest, &filelen);
- }
- filestart = dest.pos;
-
- if (res == 0) {
- res = read_long(&dest, &val);
- }
- if (res == 0 && val != IFFID('I', 'F', 'Z', 'S')) { /* ### ? */
- /* ### bad header */
- return 1;
- }
-
- while (res == 0 && dest.pos < filestart+filelen) {
- /* Read a chunk and deal with it. */
- uint chunktype=0, chunkstart=0, chunklen=0;
- unsigned char dummy;
-
- if (res == 0) {
- res = read_long(&dest, &chunktype);
- }
- if (res == 0) {
- res = read_long(&dest, &chunklen);
- }
- chunkstart = dest.pos;
-
- if (chunktype == IFFID('I', 'F', 'h', 'd')) {
- for (ix=0; res==0 && ix<128; ix++) {
- res = read_byte(&dest, &dummy);
- if (res == 0 && Mem1(ix) != dummy) {
- /* ### non-matching header */
- return 1;
- }
- }
- }
- else if (chunktype == IFFID('C', 'M', 'e', 'm')) {
- res = read_memstate(&dest, chunklen);
- }
- else if (chunktype == IFFID('M', 'A', 'l', 'l')) {
- res = read_heapstate(&dest, chunklen, true, &heapsumlen, &heapsumarr);
- }
- else if (chunktype == IFFID('S', 't', 'k', 's')) {
- res = read_stackstate(&dest, chunklen, true);
- }
- else {
- /* Unknown chunk type. Skip it. */
- for (lx=0; res==0 && lx<chunklen; lx++) {
- res = read_byte(&dest, &dummy);
- }
- }
-
- if (chunkstart+chunklen != dest.pos) {
- /* ### funny chunk length */
- return 1;
- }
-
- if ((chunklen & 1) != 0) {
- if (res == 0) {
- res = read_byte(&dest, &dummy);
- }
- }
- }
-
- if (res == 0) {
- if (heapsumarr) {
- /* The summary might have come from any interpreter, so it could
- be out of order. We'll sort it. */
- glulx_sort(heapsumarr+2, (heapsumlen-2)/2, 2*sizeof(uint), &sort_heap_summary);
- res = heap_apply_summary(heapsumlen, heapsumarr);
- }
- }
-
- if (res)
- return 1;
-
- return 0;
+ dest_t dest;
+ int ix;
+ uint lx, res, val;
+ uint filestart, filelen = 0;
+ uint heapsumlen = 0;
+ uint *heapsumarr = nullptr;
+
+ /* If profiling is enabled and active then fail. */
+#if VM_PROFILING
+ if (profile_profiling_active())
+ return 1;
+#endif /* VM_PROFILING */
+
+ stream_get_iosys(&val, &lx);
+ if (val != 2 && !fromshell) {
+ /* Not using the Glk I/O system, so bail. This function only
+ knows how to read from a Glk stream. (But in the autorestore
+ case, iosys hasn't been set yet, so ignore this test.) */
+ fatal_error("Streams are only available in Glk I/O system.");
+ }
+
+ if (str == 0)
+ return 1;
+
+ dest.ismem = false;
+ dest.size = 0;
+ dest.pos = 0;
+ dest.ptr = nullptr;
+ dest.str = str;
+
+ res = 0;
+
+ /* ### the format errors checked below should send error messages to
+ the current stream. */
+
+ if (res == 0) {
+ res = read_long(&dest, &val);
+ }
+ if (res == 0 && val != IFFID('F', 'O', 'R', 'M')) {
+ /* ### bad header */
+ return 1;
+ }
+ if (res == 0) {
+ res = read_long(&dest, &filelen);
+ }
+ filestart = dest.pos;
+
+ if (res == 0) {
+ res = read_long(&dest, &val);
+ }
+ if (res == 0 && val != IFFID('I', 'F', 'Z', 'S')) { /* ### ? */
+ /* ### bad header */
+ return 1;
+ }
+
+ while (res == 0 && dest.pos < filestart + filelen) {
+ /* Read a chunk and deal with it. */
+ uint chunktype = 0, chunkstart = 0, chunklen = 0;
+ unsigned char dummy;
+
+ if (res == 0) {
+ res = read_long(&dest, &chunktype);
+ }
+ if (res == 0) {
+ res = read_long(&dest, &chunklen);
+ }
+ chunkstart = dest.pos;
+
+ if (chunktype == IFFID('I', 'F', 'h', 'd')) {
+ for (ix = 0; res == 0 && ix < 128; ix++) {
+ res = read_byte(&dest, &dummy);
+ if (res == 0 && Mem1(ix) != dummy) {
+ /* ### non-matching header */
+ return 1;
+ }
+ }
+ } else if (chunktype == IFFID('C', 'M', 'e', 'm')) {
+ res = read_memstate(&dest, chunklen);
+ } else if (chunktype == IFFID('M', 'A', 'l', 'l')) {
+ res = read_heapstate(&dest, chunklen, true, &heapsumlen, &heapsumarr);
+ } else if (chunktype == IFFID('S', 't', 'k', 's')) {
+ res = read_stackstate(&dest, chunklen, true);
+ } else {
+ /* Unknown chunk type. Skip it. */
+ for (lx = 0; res == 0 && lx < chunklen; lx++) {
+ res = read_byte(&dest, &dummy);
+ }
+ }
+
+ if (chunkstart + chunklen != dest.pos) {
+ /* ### funny chunk length */
+ return 1;
+ }
+
+ if ((chunklen & 1) != 0) {
+ if (res == 0) {
+ res = read_byte(&dest, &dummy);
+ }
+ }
+ }
+
+ if (res == 0) {
+ if (heapsumarr) {
+ /* The summary might have come from any interpreter, so it could
+ be out of order. We'll sort it. */
+ glulx_sort(heapsumarr + 2, (heapsumlen - 2) / 2, 2 * sizeof(uint), &sort_heap_summary);
+ res = heap_apply_summary(heapsumlen, heapsumarr);
+ }
+ }
+
+ if (res)
+ return 1;
+
+ return 0;
}
int Glulxe::reposition_write(dest_t *dest, uint pos) {
- if (dest->ismem) {
- dest->pos = pos;
- } else {
- glk_stream_set_position(dest->str, pos, seekmode_Start);
- dest->pos = pos;
- }
-
- return 0;
+ if (dest->ismem) {
+ dest->pos = pos;
+ } else {
+ glk_stream_set_position(dest->str, pos, seekmode_Start);
+ dest->pos = pos;
+ }
+
+ return 0;
}
int Glulxe::write_buffer(dest_t *dest, const byte *ptr, uint len) {
- if (dest->ismem) {
- if (dest->pos+len > dest->size) {
- dest->size = dest->pos+len+1024;
- if (!dest->ptr) {
- dest->ptr = (byte *)glulx_malloc(dest->size);
- } else {
- dest->ptr = (byte *)glulx_realloc(dest->ptr, dest->size);
- }
- if (!dest->ptr)
- return 1;
- }
- memcpy(dest->ptr+dest->pos, ptr, len);
- }
- else {
- glk_put_buffer_stream(dest->str, (char *)ptr, len);
- }
-
- dest->pos += len;
-
- return 0;
+ if (dest->ismem) {
+ if (dest->pos + len > dest->size) {
+ dest->size = dest->pos + len + 1024;
+ if (!dest->ptr) {
+ dest->ptr = (byte *)glulx_malloc(dest->size);
+ } else {
+ dest->ptr = (byte *)glulx_realloc(dest->ptr, dest->size);
+ }
+ if (!dest->ptr)
+ return 1;
+ }
+ memcpy(dest->ptr + dest->pos, ptr, len);
+ } else {
+ glk_put_buffer_stream(dest->str, (char *)ptr, len);
+ }
+
+ dest->pos += len;
+
+ return 0;
}
int Glulxe::read_buffer(dest_t *dest, byte *ptr, uint len) {
- uint newlen;
+ uint newlen;
- if (dest->ismem) {
- memcpy(ptr, dest->ptr+dest->pos, len);
- }
- else {
- newlen = glk_get_buffer_stream(dest->str, (char *)ptr, len);
- if (newlen != len)
- return 1;
- }
+ if (dest->ismem) {
+ memcpy(ptr, dest->ptr + dest->pos, len);
+ } else {
+ newlen = glk_get_buffer_stream(dest->str, (char *)ptr, len);
+ if (newlen != len)
+ return 1;
+ }
- dest->pos += len;
+ dest->pos += len;
- return 0;
+ return 0;
}
int Glulxe::write_long(dest_t *dest, uint val) {
- unsigned char buf[4];
- Write4(buf, val);
- return write_buffer(dest, buf, 4);
+ unsigned char buf[4];
+ Write4(buf, val);
+ return write_buffer(dest, buf, 4);
}
int Glulxe::write_short(dest_t *dest, uint16 val) {
- unsigned char buf[2];
- Write2(buf, val);
- return write_buffer(dest, buf, 2);
+ unsigned char buf[2];
+ Write2(buf, val);
+ return write_buffer(dest, buf, 2);
}
int Glulxe::write_byte(dest_t *dest, byte val) {
- return write_buffer(dest, &val, 1);
+ return write_buffer(dest, &val, 1);
}
int Glulxe::read_long(dest_t *dest, uint *val) {
- unsigned char buf[4];
- int res = read_buffer(dest, buf, 4);
- if (res)
- return res;
- *val = Read4(buf);
- return 0;
+ unsigned char buf[4];
+ int res = read_buffer(dest, buf, 4);
+ if (res)
+ return res;
+ *val = Read4(buf);
+ return 0;
}
int Glulxe::read_short(dest_t *dest, uint16 *val) {
- unsigned char buf[2];
- int res = read_buffer(dest, buf, 2);
- if (res)
- return res;
- *val = Read2(buf);
- return 0;
+ unsigned char buf[2];
+ int res = read_buffer(dest, buf, 2);
+ if (res)
+ return res;
+ *val = Read2(buf);
+ return 0;
}
int Glulxe::read_byte(dest_t *dest, byte *val) {
- return read_buffer(dest, val, 1);
+ return read_buffer(dest, val, 1);
}
uint Glulxe::write_memstate(dest_t *dest) {
- uint res, pos;
- int val;
- int runlen;
- unsigned char ch;
+ uint res, pos;
+ int val;
+ int runlen;
+ unsigned char ch;
#ifdef SERIALIZE_CACHE_RAM
- uint cachepos;
+ uint cachepos;
#endif /* SERIALIZE_CACHE_RAM */
- res = write_long(dest, endmem);
- if (res)
- return res;
+ res = write_long(dest, endmem);
+ if (res)
+ return res;
- runlen = 0;
+ runlen = 0;
#ifdef SERIALIZE_CACHE_RAM
- cachepos = 0;
+ cachepos = 0;
#else /* SERIALIZE_CACHE_RAM */
- _gameFile.seek(gamefile_start + ramstart);
+ _gameFile.seek(gamefile_start + ramstart);
#endif /* SERIALIZE_CACHE_RAM */
- for (pos=ramstart; pos<endmem; pos++) {
- ch = Mem1(pos);
- if (pos < endgamefile) {
+ for (pos = ramstart; pos < endmem; pos++) {
+ ch = Mem1(pos);
+ if (pos < endgamefile) {
#ifdef SERIALIZE_CACHE_RAM
- val = ramcache[cachepos];
- cachepos++;
+ val = ramcache[cachepos];
+ cachepos++;
#else /* SERIALIZE_CACHE_RAM */
- val = glk_get_char_stream(gamefile);
- if (val == -1) {
- fatal_error("The game file ended unexpectedly while saving.");
- }
+ val = glk_get_char_stream(gamefile);
+ if (val == -1) {
+ fatal_error("The game file ended unexpectedly while saving.");
+ }
#endif /* SERIALIZE_CACHE_RAM */
- ch ^= (unsigned char)val;
- }
- if (ch == 0) {
- runlen++;
- }
- else {
- /* Write any run we've got. */
- while (runlen) {
- if (runlen >= 0x100)
- val = 0x100;
- else
- val = runlen;
- res = write_byte(dest, 0);
- if (res)
- return res;
- res = write_byte(dest, (val-1));
- if (res)
- return res;
- runlen -= val;
- }
- /* Write the byte we got. */
- res = write_byte(dest, ch);
- if (res)
- return res;
- }
- }
- /* It's possible we've got a run left over, but we don't write it. */
-
- return 0;
+ ch ^= (unsigned char)val;
+ }
+ if (ch == 0) {
+ runlen++;
+ } else {
+ /* Write any run we've got. */
+ while (runlen) {
+ if (runlen >= 0x100)
+ val = 0x100;
+ else
+ val = runlen;
+ res = write_byte(dest, 0);
+ if (res)
+ return res;
+ res = write_byte(dest, (val - 1));
+ if (res)
+ return res;
+ runlen -= val;
+ }
+ /* Write the byte we got. */
+ res = write_byte(dest, ch);
+ if (res)
+ return res;
+ }
+ }
+ /* It's possible we've got a run left over, but we don't write it. */
+
+ return 0;
}
uint Glulxe::read_memstate(dest_t *dest, uint chunklen) {
- uint chunkend = dest->pos + chunklen;
- uint newlen;
- uint res, pos;
- int val;
- int runlen;
- unsigned char ch, ch2;
+ uint chunkend = dest->pos + chunklen;
+ uint newlen;
+ uint res, pos;
+ int val;
+ int runlen;
+ unsigned char ch, ch2;
#ifdef SERIALIZE_CACHE_RAM
- uint cachepos;
+ uint cachepos;
#endif /* SERIALIZE_CACHE_RAM */
- heap_clear();
+ heap_clear();
- res = read_long(dest, &newlen);
- if (res)
- return res;
+ res = read_long(dest, &newlen);
+ if (res)
+ return res;
- res = change_memsize(newlen, false);
- if (res)
- return res;
+ res = change_memsize(newlen, false);
+ if (res)
+ return res;
- runlen = 0;
+ runlen = 0;
#ifdef SERIALIZE_CACHE_RAM
- cachepos = 0;
+ cachepos = 0;
#else /* SERIALIZE_CACHE_RAM */
- _gameFile.seek(gamefile_start + ramstart);
+ _gameFile.seek(gamefile_start + ramstart);
#endif /* SERIALIZE_CACHE_RAM */
- for (pos=ramstart; pos<endmem; pos++) {
- if (pos < endgamefile) {
+ for (pos = ramstart; pos < endmem; pos++) {
+ if (pos < endgamefile) {
#ifdef SERIALIZE_CACHE_RAM
- val = ramcache[cachepos];
- cachepos++;
+ val = ramcache[cachepos];
+ cachepos++;
#else /* SERIALIZE_CACHE_RAM */
- if (_gameFile.pos() >= _gameFile.size()) {
- fatal_error("The game file ended unexpectedly while restoring.");
- val = _gameFile.readByte();
- }
+ if (_gameFile.pos() >= _gameFile.size()) {
+ fatal_error("The game file ended unexpectedly while restoring.");
+ val = _gameFile.readByte();
+ }
#endif /* SERIALIZE_CACHE_RAM */
- ch = (unsigned char)val;
- } else {
- ch = 0;
- }
-
- if (dest->pos >= chunkend) {
- /* we're into the final, unstored run. */
- }
- else if (runlen) {
- runlen--;
- }
- else {
- res = read_byte(dest, &ch2);
- if (res)
- return res;
- if (ch2 == 0) {
- res = read_byte(dest, &ch2);
- if (res)
- return res;
- runlen = (uint)ch2;
- }
- else {
- ch ^= ch2;
- }
- }
-
- if (pos >= protectstart && pos < protectend)
- continue;
-
- MemW1(pos, ch);
- }
-
- return 0;
+ ch = (unsigned char)val;
+ } else {
+ ch = 0;
+ }
+
+ if (dest->pos >= chunkend) {
+ /* we're into the final, unstored run. */
+ } else if (runlen) {
+ runlen--;
+ } else {
+ res = read_byte(dest, &ch2);
+ if (res)
+ return res;
+ if (ch2 == 0) {
+ res = read_byte(dest, &ch2);
+ if (res)
+ return res;
+ runlen = (uint)ch2;
+ } else {
+ ch ^= ch2;
+ }
+ }
+
+ if (pos >= protectstart && pos < protectend)
+ continue;
+
+ MemW1(pos, ch);
+ }
+
+ return 0;
}
uint Glulxe::write_heapstate(dest_t *dest, int portable) {
- uint res;
- uint sumlen;
- uint *sumarray;
+ uint res;
+ uint sumlen;
+ uint *sumarray;
- res = heap_get_summary(&sumlen, &sumarray);
- if (res)
- return res;
+ res = heap_get_summary(&sumlen, &sumarray);
+ if (res)
+ return res;
- if (!sumarray)
- return 0; /* no heap */
+ if (!sumarray)
+ return 0; /* no heap */
- res = write_heapstate_sub(sumlen, sumarray, dest, portable);
+ res = write_heapstate_sub(sumlen, sumarray, dest, portable);
- glulx_free(sumarray);
- return res;
+ glulx_free(sumarray);
+ return res;
}
uint Glulxe::write_heapstate_sub(uint sumlen, uint *sumarray, dest_t *dest, int portable) {
- uint res, lx;
-
- /* If we're storing for the purpose of undo, we don't need to do any
- byte-swapping, because the result will only be used by this session. */
- if (!portable) {
- res = write_buffer(dest, (const byte *)sumarray, sumlen * sizeof(uint));
- if (res)
- return res;
- return 0;
- }
-
- for (lx=0; lx<sumlen; lx++) {
- res = write_long(dest, sumarray[lx]);
- if (res)
- return res;
- }
-
- return 0;
+ uint res, lx;
+
+ /* If we're storing for the purpose of undo, we don't need to do any
+ byte-swapping, because the result will only be used by this session. */
+ if (!portable) {
+ res = write_buffer(dest, (const byte *)sumarray, sumlen * sizeof(uint));
+ if (res)
+ return res;
+ return 0;
+ }
+
+ for (lx = 0; lx < sumlen; lx++) {
+ res = write_long(dest, sumarray[lx]);
+ if (res)
+ return res;
+ }
+
+ return 0;
}
int Glulxe::sort_heap_summary(const void *p1, const void *p2) {
- uint v1 = *(uint *)p1;
- uint v2 = *(uint *)p2;
-
- if (v1 < v2)
- return -1;
- if (v1 > v2)
- return 1;
- return 0;
+ uint v1 = *(uint *)p1;
+ uint v2 = *(uint *)p2;
+
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return 1;
+ return 0;
}
uint Glulxe::read_heapstate(dest_t *dest, uint chunklen, int portable, uint *sumlen, uint **summary) {
- uint res, count, lx;
- uint *arr;
+ uint res, count, lx;
+ uint *arr;
+
+ *sumlen = 0;
+ *summary = nullptr;
- *sumlen = 0;
- *summary = nullptr;
+ if (chunklen == 0)
+ return 0; /* no heap */
- if (chunklen == 0)
- return 0; /* no heap */
+ if (!portable) {
+ count = chunklen / sizeof(uint);
- if (!portable) {
- count = chunklen / sizeof(uint);
+ arr = (uint *)glulx_malloc(chunklen);
+ if (!arr)
+ return 1;
- arr = (uint *)glulx_malloc(chunklen);
- if (!arr)
- return 1;
+ res = read_buffer(dest, (byte *)arr, chunklen);
+ if (res)
+ return res;
- res = read_buffer(dest, (byte *)arr, chunklen);
- if (res)
- return res;
+ *sumlen = count;
+ *summary = arr;
- *sumlen = count;
- *summary = arr;
+ return 0;
+ }
- return 0;
- }
+ count = chunklen / 4;
- count = chunklen / 4;
+ arr = (uint *)glulx_malloc(count * sizeof(uint));
+ if (!arr)
+ return 1;
- arr = (uint *)glulx_malloc(count * sizeof(uint));
- if (!arr)
- return 1;
-
- for (lx=0; lx<count; lx++) {
- res = read_long(dest, arr+lx);
- if (res)
- return res;
- }
+ for (lx = 0; lx < count; lx++) {
+ res = read_long(dest, arr + lx);
+ if (res)
+ return res;
+ }
- *sumlen = count;
- *summary = arr;
+ *sumlen = count;
+ *summary = arr;
- return 0;
+ return 0;
}
uint Glulxe::write_stackstate(dest_t *dest, int portable) {
- uint res;
- uint lx;
- uint lastframe;
-
- /* If we're storing for the purpose of undo, we don't need to do any
- byte-swapping, because the result will only be used by this session. */
- if (!portable) {
- res = write_buffer(dest, stack, stackptr);
- if (res)
- return res;
- return 0;
- }
-
- /* Write a portable stack image. To do this, we have to write stack
- frames in order, bottom to top. Remember that the last word of
- every stack frame is a pointer to the beginning of that stack frame.
- (This includes the last frame, because the save opcode pushes on
- a call stub before it calls perform_save().) */
-
- lastframe = (uint)(-1);
- while (1) {
- uint frameend, frm, frm2, frm3;
- unsigned char loctype, loccount;
- uint numlocals, frlen, locpos;
-
- /* Find the next stack frame (after the one in lastframe). Sadly,
- this requires searching the stack from the top down. We have to
- do this for *every* frame, which takes N^2 time overall. But
- save routines usually aren't nested very deep.
- If it becomes a practical problem, we can build a stack-frame
- array, which requires dynamic allocation. */
- for (frm = stackptr, frameend = stackptr;
- frm != 0 && (frm2 = Stk4(frm-4)) != lastframe;
- frameend = frm, frm = frm2) { };
-
- /* Write out the frame. */
- frm2 = frm;
-
- frlen = Stk4(frm2);
- frm2 += 4;
- res = write_long(dest, frlen);
- if (res)
- return res;
- locpos = Stk4(frm2);
- frm2 += 4;
- res = write_long(dest, locpos);
- if (res)
- return res;
-
- frm3 = frm2;
-
- numlocals = 0;
- while (1) {
- loctype = Stk1(frm2);
- frm2 += 1;
- loccount = Stk1(frm2);
- frm2 += 1;
-
- res = write_byte(dest, loctype);
- if (res)
- return res;
- res = write_byte(dest, loccount);
- if (res)
- return res;
-
- if (loctype == 0 && loccount == 0)
- break;
-
- numlocals++;
- }
-
- if ((numlocals & 1) == 0) {
- res = write_byte(dest, 0);
- if (res)
- return res;
- res = write_byte(dest, 0);
- if (res)
- return res;
- frm2 += 2;
- }
-
- if (frm2 != frm+locpos)
- fatal_error("Inconsistent stack frame during save.");
-
- /* Write out the locals. */
- for (lx=0; lx<numlocals; lx++) {
- loctype = Stk1(frm3);
- frm3 += 1;
- loccount = Stk1(frm3);
- frm3 += 1;
-
- if (loctype == 0 && loccount == 0)
- break;
-
- /* Put in up to 0, 1, or 3 bytes of padding, depending on loctype. */
- while (frm2 & (loctype-1)) {
- res = write_byte(dest, 0);
- if (res)
- return res;
- frm2 += 1;
- }
-
- /* Put in this set of locals. */
- switch (loctype) {
-
- case 1:
- do {
- res = write_byte(dest, Stk1(frm2));
- if (res)
- return res;
- frm2 += 1;
- loccount--;
- } while (loccount);
- break;
-
- case 2:
- do {
- res = write_short(dest, Stk2(frm2));
- if (res)
- return res;
- frm2 += 2;
- loccount--;
- } while (loccount);
- break;
-
- case 4:
- do {
- res = write_long(dest, Stk4(frm2));
- if (res)
- return res;
- frm2 += 4;
- loccount--;
- } while (loccount);
- break;
-
- }
- }
-
- if (frm2 != frm+frlen)
- fatal_error("Inconsistent stack frame during save.");
-
- while (frm2 < frameend) {
- res = write_long(dest, Stk4(frm2));
- if (res)
- return res;
- frm2 += 4;
- }
-
- /* Go on to the next frame. */
- if (frameend == stackptr)
- break; /* All done. */
- lastframe = frm;
- }
-
- return 0;
+ uint res;
+ uint lx;
+ uint lastframe;
+
+ /* If we're storing for the purpose of undo, we don't need to do any
+ byte-swapping, because the result will only be used by this session. */
+ if (!portable) {
+ res = write_buffer(dest, stack, stackptr);
+ if (res)
+ return res;
+ return 0;
+ }
+
+ /* Write a portable stack image. To do this, we have to write stack
+ frames in order, bottom to top. Remember that the last word of
+ every stack frame is a pointer to the beginning of that stack frame.
+ (This includes the last frame, because the save opcode pushes on
+ a call stub before it calls perform_save().) */
+
+ lastframe = (uint)(-1);
+ while (1) {
+ uint frameend, frm, frm2, frm3;
+ unsigned char loctype, loccount;
+ uint numlocals, frlen, locpos;
+
+ /* Find the next stack frame (after the one in lastframe). Sadly,
+ this requires searching the stack from the top down. We have to
+ do this for *every* frame, which takes N^2 time overall. But
+ save routines usually aren't nested very deep.
+ If it becomes a practical problem, we can build a stack-frame
+ array, which requires dynamic allocation. */
+ for (frm = stackptr, frameend = stackptr;
+ frm != 0 && (frm2 = Stk4(frm - 4)) != lastframe;
+ frameend = frm, frm = frm2) { };
+
+ /* Write out the frame. */
+ frm2 = frm;
+
+ frlen = Stk4(frm2);
+ frm2 += 4;
+ res = write_long(dest, frlen);
+ if (res)
+ return res;
+ locpos = Stk4(frm2);
+ frm2 += 4;
+ res = write_long(dest, locpos);
+ if (res)
+ return res;
+
+ frm3 = frm2;
+
+ numlocals = 0;
+ while (1) {
+ loctype = Stk1(frm2);
+ frm2 += 1;
+ loccount = Stk1(frm2);
+ frm2 += 1;
+
+ res = write_byte(dest, loctype);
+ if (res)
+ return res;
+ res = write_byte(dest, loccount);
+ if (res)
+ return res;
+
+ if (loctype == 0 && loccount == 0)
+ break;
+
+ numlocals++;
+ }
+
+ if ((numlocals & 1) == 0) {
+ res = write_byte(dest, 0);
+ if (res)
+ return res;
+ res = write_byte(dest, 0);
+ if (res)
+ return res;
+ frm2 += 2;
+ }
+
+ if (frm2 != frm + locpos)
+ fatal_error("Inconsistent stack frame during save.");
+
+ /* Write out the locals. */
+ for (lx = 0; lx < numlocals; lx++) {
+ loctype = Stk1(frm3);
+ frm3 += 1;
+ loccount = Stk1(frm3);
+ frm3 += 1;
+
+ if (loctype == 0 && loccount == 0)
+ break;
+
+ /* Put in up to 0, 1, or 3 bytes of padding, depending on loctype. */
+ while (frm2 & (loctype - 1)) {
+ res = write_byte(dest, 0);
+ if (res)
+ return res;
+ frm2 += 1;
+ }
+
+ /* Put in this set of locals. */
+ switch (loctype) {
+
+ case 1:
+ do {
+ res = write_byte(dest, Stk1(frm2));
+ if (res)
+ return res;
+ frm2 += 1;
+ loccount--;
+ } while (loccount);
+ break;
+
+ case 2:
+ do {
+ res = write_short(dest, Stk2(frm2));
+ if (res)
+ return res;
+ frm2 += 2;
+ loccount--;
+ } while (loccount);
+ break;
+
+ case 4:
+ do {
+ res = write_long(dest, Stk4(frm2));
+ if (res)
+ return res;
+ frm2 += 4;
+ loccount--;
+ } while (loccount);
+ break;
+
+ }
+ }
+
+ if (frm2 != frm + frlen)
+ fatal_error("Inconsistent stack frame during save.");
+
+ while (frm2 < frameend) {
+ res = write_long(dest, Stk4(frm2));
+ if (res)
+ return res;
+ frm2 += 4;
+ }
+
+ /* Go on to the next frame. */
+ if (frameend == stackptr)
+ break; /* All done. */
+ lastframe = frm;
+ }
+
+ return 0;
}
uint Glulxe::read_stackstate(dest_t *dest, uint chunklen, int portable) {
- uint res;
- uint frameend, frm, frm2, frm3, locpos, frlen, numlocals;
-
- if (chunklen > stacksize)
- return 1;
-
- stackptr = chunklen;
- frameptr = 0;
- valstackbase = 0;
- localsbase = 0;
-
- if (!portable) {
- res = read_buffer(dest, stack, stackptr);
- if (res)
- return res;
- return 0;
- }
-
- /* This isn't going to be pleasant; we're going to read the data in
- as a block, and then convert it in-place. */
- res = read_buffer(dest, stack, stackptr);
- if (res)
- return res;
-
- frameend = stackptr;
- while (frameend != 0) {
- /* Read the beginning-of-frame pointer. Remember, right now, the
- whole frame is stored big-endian. So we have to read with the
- Read*() macros, and then write with the StkW*() macros. */
- frm = Read4(stack+(frameend-4));
-
- frm2 = frm;
-
- frlen = Read4(stack+frm2);
- StkW4(frm2, frlen);
- frm2 += 4;
- locpos = Read4(stack+frm2);
- StkW4(frm2, locpos);
- frm2 += 4;
-
- /* The locals-format list is in bytes, so we don't have to convert it. */
- frm3 = frm2;
- frm2 = frm+locpos;
-
- numlocals = 0;
-
- while (1) {
- unsigned char loctype, loccount;
- loctype = Read1(stack+frm3);
- frm3 += 1;
- loccount = Read1(stack+frm3);
- frm3 += 1;
-
- if (loctype == 0 && loccount == 0)
- break;
-
- /* Skip up to 0, 1, or 3 bytes of padding, depending on loctype. */
- while (frm2 & (loctype-1)) {
- StkW1(frm2, 0);
- frm2++;
- }
-
- /* Convert this set of locals. */
- switch (loctype) {
-
- case 1:
- do {
- /* Don't need to convert bytes. */
- frm2 += 1;
- loccount--;
- } while (loccount);
- break;
-
- case 2:
- do {
- uint16 loc = Read2(stack+frm2);
- StkW2(frm2, loc);
- frm2 += 2;
- loccount--;
- } while (loccount);
- break;
-
- case 4:
- do {
- uint loc = Read4(stack+frm2);
- StkW4(frm2, loc);
- frm2 += 4;
- loccount--;
- } while (loccount);
- break;
-
- }
-
- numlocals++;
- }
-
- if ((numlocals & 1) == 0) {
- StkW1(frm3, 0);
- frm3++;
- StkW1(frm3, 0);
- frm3++;
- }
-
- if (frm3 != frm+locpos) {
- return 1;
- }
-
- while (frm2 & 3) {
- StkW1(frm2, 0);
- frm2++;
- }
-
- if (frm2 != frm+frlen) {
- return 1;
- }
-
- /* Now, the values pushed on the stack after the call frame itself.
- This includes the stub. */
- while (frm2 < frameend) {
- uint loc = Read4(stack+frm2);
- StkW4(frm2, loc);
- frm2 += 4;
- }
-
- frameend = frm;
- }
-
- return 0;
+ uint res;
+ uint frameend, frm, frm2, frm3, locpos, frlen, numlocals;
+
+ if (chunklen > stacksize)
+ return 1;
+
+ stackptr = chunklen;
+ frameptr = 0;
+ valstackbase = 0;
+ localsbase = 0;
+
+ if (!portable) {
+ res = read_buffer(dest, stack, stackptr);
+ if (res)
+ return res;
+ return 0;
+ }
+
+ /* This isn't going to be pleasant; we're going to read the data in
+ as a block, and then convert it in-place. */
+ res = read_buffer(dest, stack, stackptr);
+ if (res)
+ return res;
+
+ frameend = stackptr;
+ while (frameend != 0) {
+ /* Read the beginning-of-frame pointer. Remember, right now, the
+ whole frame is stored big-endian. So we have to read with the
+ Read*() macros, and then write with the StkW*() macros. */
+ frm = Read4(stack + (frameend - 4));
+
+ frm2 = frm;
+
+ frlen = Read4(stack + frm2);
+ StkW4(frm2, frlen);
+ frm2 += 4;
+ locpos = Read4(stack + frm2);
+ StkW4(frm2, locpos);
+ frm2 += 4;
+
+ /* The locals-format list is in bytes, so we don't have to convert it. */
+ frm3 = frm2;
+ frm2 = frm + locpos;
+
+ numlocals = 0;
+
+ while (1) {
+ unsigned char loctype, loccount;
+ loctype = Read1(stack + frm3);
+ frm3 += 1;
+ loccount = Read1(stack + frm3);
+ frm3 += 1;
+
+ if (loctype == 0 && loccount == 0)
+ break;
+
+ /* Skip up to 0, 1, or 3 bytes of padding, depending on loctype. */
+ while (frm2 & (loctype - 1)) {
+ StkW1(frm2, 0);
+ frm2++;
+ }
+
+ /* Convert this set of locals. */
+ switch (loctype) {
+
+ case 1:
+ do {
+ /* Don't need to convert bytes. */
+ frm2 += 1;
+ loccount--;
+ } while (loccount);
+ break;
+
+ case 2:
+ do {
+ uint16 loc = Read2(stack + frm2);
+ StkW2(frm2, loc);
+ frm2 += 2;
+ loccount--;
+ } while (loccount);
+ break;
+
+ case 4:
+ do {
+ uint loc = Read4(stack + frm2);
+ StkW4(frm2, loc);
+ frm2 += 4;
+ loccount--;
+ } while (loccount);
+ break;
+
+ }
+
+ numlocals++;
+ }
+
+ if ((numlocals & 1) == 0) {
+ StkW1(frm3, 0);
+ frm3++;
+ StkW1(frm3, 0);
+ frm3++;
+ }
+
+ if (frm3 != frm + locpos) {
+ return 1;
+ }
+
+ while (frm2 & 3) {
+ StkW1(frm2, 0);
+ frm2++;
+ }
+
+ if (frm2 != frm + frlen) {
+ return 1;
+ }
+
+ /* Now, the values pushed on the stack after the call frame itself.
+ This includes the stub. */
+ while (frm2 < frameend) {
+ uint loc = Read4(stack + frm2);
+ StkW4(frm2, loc);
+ frm2 += 4;
+ }
+
+ frameend = frm;
+ }
+
+ return 0;
}
uint Glulxe::perform_verify() {
- uint len, chksum = 0, newlen;
- unsigned char buf[4];
- uint val, newsum, ix;
-
- len = gamefile_len;
-
- if (len < 256 || (len & 0xFF) != 0)
- return 1;
-
- _gameFile.seek(gamefile_start);
- newsum = 0;
-
- /* Read the header */
- for (ix=0; ix<9; ix++) {
- newlen = _gameFile.read(buf, 4);
- if (newlen != 4)
- return 1;
- val = Read4(buf);
- if (ix == 3) {
- if (len != val)
- return 1;
- }
- if (ix == 8)
- chksum = val;
- else
- newsum += val;
- }
-
- /* Read everything else */
- for (; ix < len/4; ix++) {
- newlen = _gameFile.read(buf, 4);
- if (newlen != 4)
- return 1;
- val = Read4(buf);
- newsum += val;
- }
-
- if (newsum != chksum)
- return 1;
-
- return 0;
+ uint len, chksum = 0, newlen;
+ unsigned char buf[4];
+ uint val, newsum, ix;
+
+ len = gamefile_len;
+
+ if (len < 256 || (len & 0xFF) != 0)
+ return 1;
+
+ _gameFile.seek(gamefile_start);
+ newsum = 0;
+
+ /* Read the header */
+ for (ix = 0; ix < 9; ix++) {
+ newlen = _gameFile.read(buf, 4);
+ if (newlen != 4)
+ return 1;
+ val = Read4(buf);
+ if (ix == 3) {
+ if (len != val)
+ return 1;
+ }
+ if (ix == 8)
+ chksum = val;
+ else
+ newsum += val;
+ }
+
+ /* Read everything else */
+ for (; ix < len / 4; ix++) {
+ newlen = _gameFile.read(buf, 4);
+ if (newlen != 4)
+ return 1;
+ val = Read4(buf);
+ newsum += val;
+ }
+
+ if (newsum != chksum)
+ return 1;
+
+ return 0;
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/string.cpp b/engines/glk/glulxe/string.cpp
index 67a869edaf..a24a9b8b2f 100644
--- a/engines/glk/glulxe/string.cpp
+++ b/engines/glk/glulxe/string.cpp
@@ -26,50 +26,50 @@ namespace Glk {
namespace Glulxe {
void Glulxe::stream_get_iosys(uint *mode, uint *rock) {
- *mode = iosys_mode;
- *rock = iosys_rock;
+ *mode = iosys_mode;
+ *rock = iosys_rock;
}
void Glulxe::stream_setup_unichar() {
#ifdef GLK_MODULE_UNICODE
- if (glk_gestalt(gestalt_Unicode, 0))
- glkio_unichar_han_ptr = &Glulxe::glk_put_char_uni;
- else
- glkio_unichar_han_ptr = &Glulxe::glkio_unichar_nouni_han;
+ if (glk_gestalt(gestalt_Unicode, 0))
+ glkio_unichar_han_ptr = &Glulxe::glk_put_char_uni;
+ else
+ glkio_unichar_han_ptr = &Glulxe::glkio_unichar_nouni_han;
#else /* GLK_MODULE_UNICODE */
- glkio_unichar_han_ptr = glkio_unichar_nouni_han;
+ glkio_unichar_han_ptr = glkio_unichar_nouni_han;
#endif /* GLK_MODULE_UNICODE */
}
void Glulxe::stream_set_iosys(uint mode, uint rock) {
- switch (mode) {
- default:
- mode = 0;
- /* ...and fall through to next case (no-op I/O). */
- case iosys_None:
- rock = 0;
- stream_char_handler = &Glulxe::nopio_char_han;
- stream_unichar_handler = &Glulxe::nopio_unichar_han;
- break;
- case iosys_Filter:
- stream_char_handler = &Glulxe::filio_char_han;
- stream_unichar_handler = &Glulxe::filio_unichar_han;
- break;
- case iosys_Glk:
- if (!glkio_unichar_han_ptr)
- stream_setup_unichar();
- rock = 0;
- stream_char_handler = &Glulxe::glk_put_char;
- stream_unichar_handler = glkio_unichar_han_ptr;
- break;
- }
-
- iosys_mode = mode;
- iosys_rock = rock;
+ switch (mode) {
+ default:
+ mode = 0;
+ /* ...and fall through to next case (no-op I/O). */
+ case iosys_None:
+ rock = 0;
+ stream_char_handler = &Glulxe::nopio_char_han;
+ stream_unichar_handler = &Glulxe::nopio_unichar_han;
+ break;
+ case iosys_Filter:
+ stream_char_handler = &Glulxe::filio_char_han;
+ stream_unichar_handler = &Glulxe::filio_unichar_han;
+ break;
+ case iosys_Glk:
+ if (!glkio_unichar_han_ptr)
+ stream_setup_unichar();
+ rock = 0;
+ stream_char_handler = &Glulxe::glk_put_char;
+ stream_unichar_handler = glkio_unichar_han_ptr;
+ break;
+ }
+
+ iosys_mode = mode;
+ iosys_rock = rock;
}
void Glulxe::nopio_char_han(unsigned char ch) {
@@ -79,749 +79,728 @@ void Glulxe::nopio_unichar_han(uint ch) {
}
void Glulxe::filio_char_han(unsigned char ch) {
- uint val = ch;
- push_callstub(0, 0);
- enter_function(iosys_rock, 1, &val);
+ uint val = ch;
+ push_callstub(0, 0);
+ enter_function(iosys_rock, 1, &val);
}
void Glulxe::filio_unichar_han(uint val) {
- push_callstub(0, 0);
- enter_function(iosys_rock, 1, &val);
+ push_callstub(0, 0);
+ enter_function(iosys_rock, 1, &val);
}
void Glulxe::glkio_unichar_nouni_han(uint val) {
- /* Only used if the Glk library has no Unicode functions */
- if (val > 0xFF)
- val = '?';
- glk_put_char(val);
+ /* Only used if the Glk library has no Unicode functions */
+ if (val > 0xFF)
+ val = '?';
+ glk_put_char(val);
}
void Glulxe::stream_num(int val, int inmiddle, int charnum) {
- int ix = 0;
- int res, jx;
- char buf[16];
- uint ival;
-
- if (val == 0) {
- buf[ix] = '0';
- ix++;
- }
- else {
- if (val < 0)
- ival = -val;
- else
- ival = val;
-
- while (ival != 0) {
- buf[ix] = (ival % 10) + '0';
- ix++;
- ival /= 10;
- }
-
- if (val < 0) {
- buf[ix] = '-';
- ix++;
- }
- }
-
- switch (iosys_mode) {
-
- case iosys_Glk:
- ix -= charnum;
- while (ix > 0) {
- ix--;
- glk_put_char(buf[ix]);
- }
- break;
-
- case iosys_Filter:
- if (!inmiddle) {
- push_callstub(0x11, 0);
- inmiddle = true;
- }
- if (charnum < ix) {
- ival = buf[(ix-1)-charnum] & 0xFF;
- pc = val;
- push_callstub(0x12, charnum+1);
- enter_function(iosys_rock, 1, &ival);
- return;
- }
- break;
-
- default:
- break;
-
- }
-
- if (inmiddle) {
- res = pop_callstub_string(&jx);
- if (res)
- fatal_error("String-on-string call stub while printing number.");
- }
+ int ix = 0;
+ int res, jx;
+ char buf[16];
+ uint ival;
+
+ if (val == 0) {
+ buf[ix] = '0';
+ ix++;
+ } else {
+ if (val < 0)
+ ival = -val;
+ else
+ ival = val;
+
+ while (ival != 0) {
+ buf[ix] = (ival % 10) + '0';
+ ix++;
+ ival /= 10;
+ }
+
+ if (val < 0) {
+ buf[ix] = '-';
+ ix++;
+ }
+ }
+
+ switch (iosys_mode) {
+
+ case iosys_Glk:
+ ix -= charnum;
+ while (ix > 0) {
+ ix--;
+ glk_put_char(buf[ix]);
+ }
+ break;
+
+ case iosys_Filter:
+ if (!inmiddle) {
+ push_callstub(0x11, 0);
+ inmiddle = true;
+ }
+ if (charnum < ix) {
+ ival = buf[(ix - 1) - charnum] & 0xFF;
+ pc = val;
+ push_callstub(0x12, charnum + 1);
+ enter_function(iosys_rock, 1, &ival);
+ return;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (inmiddle) {
+ res = pop_callstub_string(&jx);
+ if (res)
+ fatal_error("String-on-string call stub while printing number.");
+ }
}
void Glulxe::stream_string(uint addr, int inmiddle, int bitnum) {
- int ch;
- int type;
- int alldone = false;
- int substring = (inmiddle != 0);
- uint ival;
-
- if (!addr)
- fatal_error("Called stream_string with null address.");
-
- while (!alldone) {
-
- if (inmiddle == 0) {
- type = Mem1(addr);
- if (type == 0xE2)
- addr+=4;
- else
- addr++;
- bitnum = 0;
- }
- else {
- type = inmiddle;
- }
-
- if (type == 0xE1) {
- if (tablecache_valid) {
- int bits, numbits;
- int readahead;
- uint tmpaddr;
- cacheblock_t *cablist;
- int done = 0;
-
- /* bitnum is already set right */
- bits = Mem1(addr);
- if (bitnum)
- bits >>= bitnum;
- numbits = (8 - bitnum);
- readahead = false;
-
- if (tablecache.type != 0) {
- /* This is a bit of a cheat. If the top-level block is not
- a branch, then it must be a string-terminator -- otherwise
- the string would be an infinite repetition of that block.
- We check for this case and bail immediately. */
- done = 1;
- }
-
- cablist = tablecache.u.branches;
- while (!done) {
- cacheblock_t *cab;
-
- if (numbits < CACHEBITS) {
- /* readahead is certainly false */
- int newbyte = Mem1(addr+1);
- bits |= (newbyte << numbits);
- numbits += 8;
- readahead = true;
- }
-
- cab = &(cablist[bits & CACHEMASK]);
- numbits -= cab->depth;
- bits >>= cab->depth;
- bitnum += cab->depth;
- if (bitnum >= 8) {
- addr += 1;
- bitnum -= 8;
- if (readahead) {
- readahead = false;
- }
- else {
- int newbyte = Mem1(addr);
- bits |= (newbyte << numbits);
- numbits += 8;
- }
- }
-
- switch (cab->type) {
- case 0x00: /* non-leaf node */
- cablist = cab->u.branches;
- break;
- case 0x01: /* string terminator */
- done = 1;
- break;
- case 0x02: /* single character */
- switch (iosys_mode) {
- case iosys_Glk:
- glk_put_char(cab->u.ch);
- break;
- case iosys_Filter:
- ival = cab->u.ch & 0xFF;
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- enter_function(iosys_rock, 1, &ival);
- return;
- }
- cablist = tablecache.u.branches;
- break;
- case 0x04: /* single Unicode character */
- switch (iosys_mode) {
- case iosys_Glk:
- (this->*glkio_unichar_han_ptr)(cab->u.uch);
- break;
- case iosys_Filter:
- ival = cab->u.uch;
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- enter_function(iosys_rock, 1, &ival);
- return;
- }
- cablist = tablecache.u.branches;
- break;
- case 0x03: /* C string */
- switch (iosys_mode) {
- case iosys_Glk:
- for (tmpaddr=cab->u.addr; (ch=Mem1(tmpaddr)) != '\0'; tmpaddr++)
- glk_put_char(ch);
- cablist = tablecache.u.branches;
- break;
- case iosys_Filter:
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- inmiddle = 0xE0;
- addr = cab->u.addr;
- done = 2;
- break;
- default:
- cablist = tablecache.u.branches;
- break;
- }
- break;
- case 0x05: /* C Unicode string */
- switch (iosys_mode) {
- case iosys_Glk:
- for (tmpaddr=cab->u.addr; (ival=Mem4(tmpaddr)) != 0; tmpaddr+=4)
- (this->*glkio_unichar_han_ptr)(ival);
- cablist = tablecache.u.branches;
- break;
- case iosys_Filter:
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- inmiddle = 0xE2;
- addr = cab->u.addr;
- done = 2;
- break;
- default:
- cablist = tablecache.u.branches;
- break;
- }
- break;
- case 0x08:
- case 0x09:
- case 0x0A:
- case 0x0B:
- {
- uint oaddr;
- int otype;
- oaddr = cab->u.addr;
- if (cab->type >= 0x09)
- oaddr = Mem4(oaddr);
- if (cab->type == 0x0B)
- oaddr = Mem4(oaddr);
- otype = Mem1(oaddr);
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- if (otype >= 0xE0 && otype <= 0xFF) {
- pc = addr;
- push_callstub(0x10, bitnum);
- inmiddle = 0;
- addr = oaddr;
- done = 2;
- }
- else if (otype >= 0xC0 && otype <= 0xDF) {
- uint argc;
- uint *argv;
- if (cab->type == 0x0A || cab->type == 0x0B) {
- argc = Mem4(cab->u.addr+4);
- argv = pop_arguments(argc, cab->u.addr+8);
- }
- else {
- argc = 0;
- argv = nullptr;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- enter_function(oaddr, argc, argv);
- return;
- }
- else {
- fatal_error("Unknown object while decoding string indirect reference.");
- }
- }
- break;
- default:
- fatal_error("Unknown entity in string decoding (cached).");
- break;
- }
- }
- if (done > 1) {
- continue; /* restart the top-level loop */
- }
- }
- else { /* tablecache not valid */
- uint node;
- int byte1;
- int nodetype;
- int done = 0;
-
- if (!stringtable)
- fatal_error("Attempted to print a compressed string with no table set.");
- /* bitnum is already set right */
- byte1 = Mem1(addr);
- if (bitnum)
- byte1 >>= bitnum;
- node = Mem4(stringtable+8);
- while (!done) {
- nodetype = Mem1(node);
- node++;
- switch (nodetype) {
- case 0x00: /* non-leaf node */
- if (byte1 & 1)
- node = Mem4(node+4);
- else
- node = Mem4(node+0);
- if (bitnum == 7) {
- bitnum = 0;
- addr++;
- byte1 = Mem1(addr);
- }
- else {
- bitnum++;
- byte1 >>= 1;
- }
- break;
- case 0x01: /* string terminator */
- done = 1;
- break;
- case 0x02: /* single character */
- ch = Mem1(node);
- switch (iosys_mode) {
- case iosys_Glk:
- glk_put_char(ch);
- break;
- case iosys_Filter:
- ival = ch & 0xFF;
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- enter_function(iosys_rock, 1, &ival);
- return;
- }
- node = Mem4(stringtable+8);
- break;
- case 0x04: /* single Unicode character */
- ival = Mem4(node);
- switch (iosys_mode) {
- case iosys_Glk:
- (this->*glkio_unichar_han_ptr)(ival);
- break;
- case iosys_Filter:
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- enter_function(iosys_rock, 1, &ival);
- return;
- }
- node = Mem4(stringtable+8);
- break;
- case 0x03: /* C string */
- switch (iosys_mode) {
- case iosys_Glk:
- for (; (ch=Mem1(node)) != '\0'; node++)
- glk_put_char(ch);
- node = Mem4(stringtable+8);
- break;
- case iosys_Filter:
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- inmiddle = 0xE0;
- addr = node;
- done = 2;
- break;
- default:
- node = Mem4(stringtable+8);
- break;
- }
- break;
- case 0x05: /* C Unicode string */
- switch (iosys_mode) {
- case iosys_Glk:
- for (; (ival=Mem4(node)) != 0; node+=4)
- (this->*glkio_unichar_han_ptr)(ival);
- node = Mem4(stringtable+8);
- break;
- case iosys_Filter:
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- inmiddle = 0xE2;
- addr = node;
- done = 2;
- break;
- default:
- node = Mem4(stringtable+8);
- break;
- }
- break;
- case 0x08:
- case 0x09:
- case 0x0A:
- case 0x0B:
- {
- uint oaddr;
- int otype;
- oaddr = Mem4(node);
- if (nodetype == 0x09 || nodetype == 0x0B)
- oaddr = Mem4(oaddr);
- otype = Mem1(oaddr);
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- if (otype >= 0xE0 && otype <= 0xFF) {
- pc = addr;
- push_callstub(0x10, bitnum);
- inmiddle = 0;
- addr = oaddr;
- done = 2;
- }
- else if (otype >= 0xC0 && otype <= 0xDF) {
- uint argc;
- uint *argv;
- if (nodetype == 0x0A || nodetype == 0x0B) {
- argc = Mem4(node+4);
- argv = pop_arguments(argc, node+8);
- }
- else {
- argc = 0;
- argv = nullptr;
- }
- pc = addr;
- push_callstub(0x10, bitnum);
- enter_function(oaddr, argc, argv);
- return;
- }
- else {
- fatal_error("Unknown object while decoding string indirect reference.");
- }
- }
- break;
- default:
- fatal_error("Unknown entity in string decoding.");
- break;
- }
- }
- if (done > 1) {
- continue; /* restart the top-level loop */
- }
- }
- }
- else if (type == 0xE0) {
- switch (iosys_mode) {
- case iosys_Glk:
- while (1) {
- ch = Mem1(addr);
- addr++;
- if (ch == '\0')
- break;
- glk_put_char(ch);
- }
- break;
- case iosys_Filter:
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- ch = Mem1(addr);
- addr++;
- if (ch != '\0') {
- ival = ch & 0xFF;
- pc = addr;
- push_callstub(0x13, 0);
- enter_function(iosys_rock, 1, &ival);
- return;
- }
- break;
- }
- }
- else if (type == 0xE2) {
- switch (iosys_mode) {
- case iosys_Glk:
- while (1) {
- ival = Mem4(addr);
- addr+=4;
- if (ival == 0)
- break;
- (this->*glkio_unichar_han_ptr)(ival);
- }
- break;
- case iosys_Filter:
- if (!substring) {
- push_callstub(0x11, 0);
- substring = true;
- }
- ival = Mem4(addr);
- addr+=4;
- if (ival != 0) {
- pc = addr;
- push_callstub(0x14, 0);
- enter_function(iosys_rock, 1, &ival);
- return;
- }
- break;
- }
- }
- else if (type >= 0xE0 && type <= 0xFF) {
- fatal_error("Attempt to print unknown type of string.");
- }
- else {
- fatal_error("Attempt to print non-string.");
- }
-
- if (!substring) {
- /* Just get straight out. */
- alldone = true;
- }
- else {
- /* Pop a stub and see what's to be done. */
- addr = pop_callstub_string(&bitnum);
- if (addr == 0) {
- alldone = true;
- }
- else {
- inmiddle = 0xE1;
- }
- }
- }
+ int ch;
+ int type;
+ int alldone = false;
+ int substring = (inmiddle != 0);
+ uint ival;
+
+ if (!addr)
+ fatal_error("Called stream_string with null address.");
+
+ while (!alldone) {
+
+ if (inmiddle == 0) {
+ type = Mem1(addr);
+ if (type == 0xE2)
+ addr += 4;
+ else
+ addr++;
+ bitnum = 0;
+ } else {
+ type = inmiddle;
+ }
+
+ if (type == 0xE1) {
+ if (tablecache_valid) {
+ int bits, numbits;
+ int readahead;
+ uint tmpaddr;
+ cacheblock_t *cablist;
+ int done = 0;
+
+ /* bitnum is already set right */
+ bits = Mem1(addr);
+ if (bitnum)
+ bits >>= bitnum;
+ numbits = (8 - bitnum);
+ readahead = false;
+
+ if (tablecache.type != 0) {
+ /* This is a bit of a cheat. If the top-level block is not
+ a branch, then it must be a string-terminator -- otherwise
+ the string would be an infinite repetition of that block.
+ We check for this case and bail immediately. */
+ done = 1;
+ }
+
+ cablist = tablecache.u.branches;
+ while (!done) {
+ cacheblock_t *cab;
+
+ if (numbits < CACHEBITS) {
+ /* readahead is certainly false */
+ int newbyte = Mem1(addr + 1);
+ bits |= (newbyte << numbits);
+ numbits += 8;
+ readahead = true;
+ }
+
+ cab = &(cablist[bits & CACHEMASK]);
+ numbits -= cab->depth;
+ bits >>= cab->depth;
+ bitnum += cab->depth;
+ if (bitnum >= 8) {
+ addr += 1;
+ bitnum -= 8;
+ if (readahead) {
+ readahead = false;
+ } else {
+ int newbyte = Mem1(addr);
+ bits |= (newbyte << numbits);
+ numbits += 8;
+ }
+ }
+
+ switch (cab->type) {
+ case 0x00: /* non-leaf node */
+ cablist = cab->u.branches;
+ break;
+ case 0x01: /* string terminator */
+ done = 1;
+ break;
+ case 0x02: /* single character */
+ switch (iosys_mode) {
+ case iosys_Glk:
+ glk_put_char(cab->u.ch);
+ break;
+ case iosys_Filter:
+ ival = cab->u.ch & 0xFF;
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ enter_function(iosys_rock, 1, &ival);
+ return;
+ }
+ cablist = tablecache.u.branches;
+ break;
+ case 0x04: /* single Unicode character */
+ switch (iosys_mode) {
+ case iosys_Glk:
+ (this->*glkio_unichar_han_ptr)(cab->u.uch);
+ break;
+ case iosys_Filter:
+ ival = cab->u.uch;
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ enter_function(iosys_rock, 1, &ival);
+ return;
+ }
+ cablist = tablecache.u.branches;
+ break;
+ case 0x03: /* C string */
+ switch (iosys_mode) {
+ case iosys_Glk:
+ for (tmpaddr = cab->u.addr; (ch = Mem1(tmpaddr)) != '\0'; tmpaddr++)
+ glk_put_char(ch);
+ cablist = tablecache.u.branches;
+ break;
+ case iosys_Filter:
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ inmiddle = 0xE0;
+ addr = cab->u.addr;
+ done = 2;
+ break;
+ default:
+ cablist = tablecache.u.branches;
+ break;
+ }
+ break;
+ case 0x05: /* C Unicode string */
+ switch (iosys_mode) {
+ case iosys_Glk:
+ for (tmpaddr = cab->u.addr; (ival = Mem4(tmpaddr)) != 0; tmpaddr += 4)
+ (this->*glkio_unichar_han_ptr)(ival);
+ cablist = tablecache.u.branches;
+ break;
+ case iosys_Filter:
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ inmiddle = 0xE2;
+ addr = cab->u.addr;
+ done = 2;
+ break;
+ default:
+ cablist = tablecache.u.branches;
+ break;
+ }
+ break;
+ case 0x08:
+ case 0x09:
+ case 0x0A:
+ case 0x0B: {
+ uint oaddr;
+ int otype;
+ oaddr = cab->u.addr;
+ if (cab->type >= 0x09)
+ oaddr = Mem4(oaddr);
+ if (cab->type == 0x0B)
+ oaddr = Mem4(oaddr);
+ otype = Mem1(oaddr);
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ if (otype >= 0xE0 && otype <= 0xFF) {
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ inmiddle = 0;
+ addr = oaddr;
+ done = 2;
+ } else if (otype >= 0xC0 && otype <= 0xDF) {
+ uint argc;
+ uint *argv;
+ if (cab->type == 0x0A || cab->type == 0x0B) {
+ argc = Mem4(cab->u.addr + 4);
+ argv = pop_arguments(argc, cab->u.addr + 8);
+ } else {
+ argc = 0;
+ argv = nullptr;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ enter_function(oaddr, argc, argv);
+ return;
+ } else {
+ fatal_error("Unknown object while decoding string indirect reference.");
+ }
+ }
+ break;
+ default:
+ fatal_error("Unknown entity in string decoding (cached).");
+ break;
+ }
+ }
+ if (done > 1) {
+ continue; /* restart the top-level loop */
+ }
+ } else { /* tablecache not valid */
+ uint node;
+ int byte1;
+ int nodetype;
+ int done = 0;
+
+ if (!stringtable)
+ fatal_error("Attempted to print a compressed string with no table set.");
+ /* bitnum is already set right */
+ byte1 = Mem1(addr);
+ if (bitnum)
+ byte1 >>= bitnum;
+ node = Mem4(stringtable + 8);
+ while (!done) {
+ nodetype = Mem1(node);
+ node++;
+ switch (nodetype) {
+ case 0x00: /* non-leaf node */
+ if (byte1 & 1)
+ node = Mem4(node + 4);
+ else
+ node = Mem4(node + 0);
+ if (bitnum == 7) {
+ bitnum = 0;
+ addr++;
+ byte1 = Mem1(addr);
+ } else {
+ bitnum++;
+ byte1 >>= 1;
+ }
+ break;
+ case 0x01: /* string terminator */
+ done = 1;
+ break;
+ case 0x02: /* single character */
+ ch = Mem1(node);
+ switch (iosys_mode) {
+ case iosys_Glk:
+ glk_put_char(ch);
+ break;
+ case iosys_Filter:
+ ival = ch & 0xFF;
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ enter_function(iosys_rock, 1, &ival);
+ return;
+ }
+ node = Mem4(stringtable + 8);
+ break;
+ case 0x04: /* single Unicode character */
+ ival = Mem4(node);
+ switch (iosys_mode) {
+ case iosys_Glk:
+ (this->*glkio_unichar_han_ptr)(ival);
+ break;
+ case iosys_Filter:
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ enter_function(iosys_rock, 1, &ival);
+ return;
+ }
+ node = Mem4(stringtable + 8);
+ break;
+ case 0x03: /* C string */
+ switch (iosys_mode) {
+ case iosys_Glk:
+ for (; (ch = Mem1(node)) != '\0'; node++)
+ glk_put_char(ch);
+ node = Mem4(stringtable + 8);
+ break;
+ case iosys_Filter:
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ inmiddle = 0xE0;
+ addr = node;
+ done = 2;
+ break;
+ default:
+ node = Mem4(stringtable + 8);
+ break;
+ }
+ break;
+ case 0x05: /* C Unicode string */
+ switch (iosys_mode) {
+ case iosys_Glk:
+ for (; (ival = Mem4(node)) != 0; node += 4)
+ (this->*glkio_unichar_han_ptr)(ival);
+ node = Mem4(stringtable + 8);
+ break;
+ case iosys_Filter:
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ inmiddle = 0xE2;
+ addr = node;
+ done = 2;
+ break;
+ default:
+ node = Mem4(stringtable + 8);
+ break;
+ }
+ break;
+ case 0x08:
+ case 0x09:
+ case 0x0A:
+ case 0x0B: {
+ uint oaddr;
+ int otype;
+ oaddr = Mem4(node);
+ if (nodetype == 0x09 || nodetype == 0x0B)
+ oaddr = Mem4(oaddr);
+ otype = Mem1(oaddr);
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ if (otype >= 0xE0 && otype <= 0xFF) {
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ inmiddle = 0;
+ addr = oaddr;
+ done = 2;
+ } else if (otype >= 0xC0 && otype <= 0xDF) {
+ uint argc;
+ uint *argv;
+ if (nodetype == 0x0A || nodetype == 0x0B) {
+ argc = Mem4(node + 4);
+ argv = pop_arguments(argc, node + 8);
+ } else {
+ argc = 0;
+ argv = nullptr;
+ }
+ pc = addr;
+ push_callstub(0x10, bitnum);
+ enter_function(oaddr, argc, argv);
+ return;
+ } else {
+ fatal_error("Unknown object while decoding string indirect reference.");
+ }
+ }
+ break;
+ default:
+ fatal_error("Unknown entity in string decoding.");
+ break;
+ }
+ }
+ if (done > 1) {
+ continue; /* restart the top-level loop */
+ }
+ }
+ } else if (type == 0xE0) {
+ switch (iosys_mode) {
+ case iosys_Glk:
+ while (1) {
+ ch = Mem1(addr);
+ addr++;
+ if (ch == '\0')
+ break;
+ glk_put_char(ch);
+ }
+ break;
+ case iosys_Filter:
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ ch = Mem1(addr);
+ addr++;
+ if (ch != '\0') {
+ ival = ch & 0xFF;
+ pc = addr;
+ push_callstub(0x13, 0);
+ enter_function(iosys_rock, 1, &ival);
+ return;
+ }
+ break;
+ }
+ } else if (type == 0xE2) {
+ switch (iosys_mode) {
+ case iosys_Glk:
+ while (1) {
+ ival = Mem4(addr);
+ addr += 4;
+ if (ival == 0)
+ break;
+ (this->*glkio_unichar_han_ptr)(ival);
+ }
+ break;
+ case iosys_Filter:
+ if (!substring) {
+ push_callstub(0x11, 0);
+ substring = true;
+ }
+ ival = Mem4(addr);
+ addr += 4;
+ if (ival != 0) {
+ pc = addr;
+ push_callstub(0x14, 0);
+ enter_function(iosys_rock, 1, &ival);
+ return;
+ }
+ break;
+ }
+ } else if (type >= 0xE0 && type <= 0xFF) {
+ fatal_error("Attempt to print unknown type of string.");
+ } else {
+ fatal_error("Attempt to print non-string.");
+ }
+
+ if (!substring) {
+ /* Just get straight out. */
+ alldone = true;
+ } else {
+ /* Pop a stub and see what's to be done. */
+ addr = pop_callstub_string(&bitnum);
+ if (addr == 0) {
+ alldone = true;
+ } else {
+ inmiddle = 0xE1;
+ }
+ }
+ }
}
uint Glulxe::stream_get_table() {
- return stringtable;
+ return stringtable;
}
void Glulxe::stream_set_table(uint addr) {
- if (stringtable == addr)
- return;
-
- /* Drop cache. */
- if (tablecache_valid) {
- if (tablecache.type == 0)
- dropcache(tablecache.u.branches);
- tablecache.u.branches = nullptr;
- tablecache_valid = false;
- }
-
- stringtable = addr;
-
- if (stringtable) {
- /* Build cache. We can only do this if the table is entirely in ROM. */
- uint tablelen = Mem4(stringtable);
- uint rootaddr = Mem4(stringtable+8);
- int cache_stringtable = (stringtable+tablelen <= ramstart);
- /* cache_stringtable = true; ...for testing only */
- /* cache_stringtable = false; ...for testing only */
- if (cache_stringtable) {
- buildcache(&tablecache, rootaddr, CACHEBITS, 0);
- /* dumpcache(&tablecache, 1, 0); */
- tablecache_valid = true;
- }
- }
+ if (stringtable == addr)
+ return;
+
+ /* Drop cache. */
+ if (tablecache_valid) {
+ if (tablecache.type == 0)
+ dropcache(tablecache.u.branches);
+ tablecache.u.branches = nullptr;
+ tablecache_valid = false;
+ }
+
+ stringtable = addr;
+
+ if (stringtable) {
+ /* Build cache. We can only do this if the table is entirely in ROM. */
+ uint tablelen = Mem4(stringtable);
+ uint rootaddr = Mem4(stringtable + 8);
+ int cache_stringtable = (stringtable + tablelen <= ramstart);
+ /* cache_stringtable = true; ...for testing only */
+ /* cache_stringtable = false; ...for testing only */
+ if (cache_stringtable) {
+ buildcache(&tablecache, rootaddr, CACHEBITS, 0);
+ /* dumpcache(&tablecache, 1, 0); */
+ tablecache_valid = true;
+ }
+ }
}
void Glulxe::buildcache(cacheblock_t *cablist, uint nodeaddr, int depth, int mask) {
- int ix, type;
-
- type = Mem1(nodeaddr);
-
- if (type == 0 && depth == CACHEBITS) {
- cacheblock_t *list, *cab;
- list = (cacheblock_t *)glulx_malloc(sizeof(cacheblock_t) * CACHESIZE);
- buildcache(list, nodeaddr, 0, 0);
- cab = &(cablist[mask]);
- cab->type = 0;
- cab->depth = CACHEBITS;
- cab->u.branches = list;
- return;
- }
-
- if (type == 0) {
- uint leftaddr = Mem4(nodeaddr+1);
- uint rightaddr = Mem4(nodeaddr+5);
- buildcache(cablist, leftaddr, depth+1, mask);
- buildcache(cablist, rightaddr, depth+1, (mask | (1 << depth)));
- return;
- }
-
- /* Leaf node. */
- nodeaddr++;
- for (ix = mask; ix < CACHESIZE; ix += (1 << depth)) {
- cacheblock_t *cab = &(cablist[ix]);
- cab->type = type;
- cab->depth = depth;
- switch (type) {
- case 0x02:
- cab->u.ch = Mem1(nodeaddr);
- break;
- case 0x04:
- cab->u.uch = Mem4(nodeaddr);
- break;
- case 0x03:
- case 0x05:
- case 0x0A:
- case 0x0B:
- cab->u.addr = nodeaddr;
- break;
- case 0x08:
- case 0x09:
- cab->u.addr = Mem4(nodeaddr);
- break;
- }
- }
+ int ix, type;
+
+ type = Mem1(nodeaddr);
+
+ if (type == 0 && depth == CACHEBITS) {
+ cacheblock_t *list, *cab;
+ list = (cacheblock_t *)glulx_malloc(sizeof(cacheblock_t) * CACHESIZE);
+ buildcache(list, nodeaddr, 0, 0);
+ cab = &(cablist[mask]);
+ cab->type = 0;
+ cab->depth = CACHEBITS;
+ cab->u.branches = list;
+ return;
+ }
+
+ if (type == 0) {
+ uint leftaddr = Mem4(nodeaddr + 1);
+ uint rightaddr = Mem4(nodeaddr + 5);
+ buildcache(cablist, leftaddr, depth + 1, mask);
+ buildcache(cablist, rightaddr, depth + 1, (mask | (1 << depth)));
+ return;
+ }
+
+ /* Leaf node. */
+ nodeaddr++;
+ for (ix = mask; ix < CACHESIZE; ix += (1 << depth)) {
+ cacheblock_t *cab = &(cablist[ix]);
+ cab->type = type;
+ cab->depth = depth;
+ switch (type) {
+ case 0x02:
+ cab->u.ch = Mem1(nodeaddr);
+ break;
+ case 0x04:
+ cab->u.uch = Mem4(nodeaddr);
+ break;
+ case 0x03:
+ case 0x05:
+ case 0x0A:
+ case 0x0B:
+ cab->u.addr = nodeaddr;
+ break;
+ case 0x08:
+ case 0x09:
+ cab->u.addr = Mem4(nodeaddr);
+ break;
+ }
+ }
}
#if 0
#include <stdio.h>
void Glulxe::dumpcache(cacheblock_t *cablist, int count, int indent) {
- int ix, jx;
-
- for (ix=0; ix<count; ix++) {
- cacheblock_t *cab = &(cablist[ix]);
- for (jx=0; jx<indent; jx++)
- printf(" ");
- printf("%X: ", ix);
- switch (cab->type) {
- case 0:
- printf("...\n");
- dumpcache(cab->u.branches, CACHESIZE, indent+1);
- break;
- case 1:
- printf("<EOS>\n");
- break;
- case 2:
- printf("0x%02X", cab->u.ch);
- if (cab->u.ch < 32)
- printf(" ''\n");
- else
- printf(" '%c'\n", cab->u.ch);
- break;
- default:
- printf("type %02X, address %06lX\n", cab->type, cab->u.addr);
- break;
- }
- }
+ int ix, jx;
+
+ for (ix = 0; ix < count; ix++) {
+ cacheblock_t *cab = &(cablist[ix]);
+ for (jx = 0; jx < indent; jx++)
+ printf(" ");
+ printf("%X: ", ix);
+ switch (cab->type) {
+ case 0:
+ printf("...\n");
+ dumpcache(cab->u.branches, CACHESIZE, indent + 1);
+ break;
+ case 1:
+ printf("<EOS>\n");
+ break;
+ case 2:
+ printf("0x%02X", cab->u.ch);
+ if (cab->u.ch < 32)
+ printf(" ''\n");
+ else
+ printf(" '%c'\n", cab->u.ch);
+ break;
+ default:
+ printf("type %02X, address %06lX\n", cab->type, cab->u.addr);
+ break;
+ }
+ }
}
#endif /* 0 */
void Glulxe::dropcache(cacheblock_t *cablist) {
- int ix;
- for (ix=0; ix<CACHESIZE; ix++) {
- cacheblock_t *cab = &(cablist[ix]);
- if (cab->type == 0) {
- dropcache(cab->u.branches);
- cab->u.branches = nullptr;
- }
- }
- glulx_free(cablist);
+ int ix;
+ for (ix = 0; ix < CACHESIZE; ix++) {
+ cacheblock_t *cab = &(cablist[ix]);
+ if (cab->type == 0) {
+ dropcache(cab->u.branches);
+ cab->u.branches = nullptr;
+ }
+ }
+ glulx_free(cablist);
}
char *Glulxe::make_temp_string(uint addr) {
- int ix, len;
- uint addr2;
- char *res;
-
- if (Mem1(addr) != 0xE0)
- fatal_error("String argument to a Glk call must be unencoded.");
- addr++;
-
- for (addr2=addr; Mem1(addr2); addr2++) { };
- len = (addr2 - addr);
- if (len < STATIC_TEMP_BUFSIZE) {
- res = temp_buf;
- }
- else {
- res = (char *)glulx_malloc(len+1);
- if (!res)
- fatal_error("Unable to allocate space for string argument to Glk call.");
- }
-
- for (ix=0, addr2=addr; ix<len; ix++, addr2++) {
- res[ix] = Mem1(addr2);
- }
- res[len] = '\0';
-
- return res;
+ int ix, len;
+ uint addr2;
+ char *res;
+
+ if (Mem1(addr) != 0xE0)
+ fatal_error("String argument to a Glk call must be unencoded.");
+ addr++;
+
+ for (addr2 = addr; Mem1(addr2); addr2++) { };
+ len = (addr2 - addr);
+ if (len < STATIC_TEMP_BUFSIZE) {
+ res = temp_buf;
+ } else {
+ res = (char *)glulx_malloc(len + 1);
+ if (!res)
+ fatal_error("Unable to allocate space for string argument to Glk call.");
+ }
+
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2++) {
+ res[ix] = Mem1(addr2);
+ }
+ res[len] = '\0';
+
+ return res;
}
uint *Glulxe::make_temp_ustring(uint addr) {
- int ix, len;
- uint addr2;
- uint *res;
-
- if (Mem1(addr) != 0xE2)
- fatal_error("Ustring argument to a Glk call must be unencoded.");
- addr+=4;
-
- for (addr2=addr; Mem4(addr2); addr2+=4) { };
- len = (addr2 - addr) / 4;
- if ((len+1)*4 < STATIC_TEMP_BUFSIZE) {
- res = (uint *)temp_buf;
- }
- else {
- res = (uint *)glulx_malloc((len+1)*4);
- if (!res)
- fatal_error("Unable to allocate space for ustring argument to Glk call.");
- }
-
- for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
- res[ix] = Mem4(addr2);
- }
- res[len] = 0;
-
- return res;
+ int ix, len;
+ uint addr2;
+ uint *res;
+
+ if (Mem1(addr) != 0xE2)
+ fatal_error("Ustring argument to a Glk call must be unencoded.");
+ addr += 4;
+
+ for (addr2 = addr; Mem4(addr2); addr2 += 4) { };
+ len = (addr2 - addr) / 4;
+ if ((len + 1) * 4 < STATIC_TEMP_BUFSIZE) {
+ res = (uint *)temp_buf;
+ } else {
+ res = (uint *)glulx_malloc((len + 1) * 4);
+ if (!res)
+ fatal_error("Unable to allocate space for ustring argument to Glk call.");
+ }
+
+ for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 4) {
+ res[ix] = Mem4(addr2);
+ }
+ res[len] = 0;
+
+ return res;
}
void Glulxe::free_temp_string(char *str) {
- if (str && str != temp_buf)
- glulx_free(str);
+ if (str && str != temp_buf)
+ glulx_free(str);
}
void Glulxe::free_temp_ustring(uint *str) {
- if (str && str != (uint *)temp_buf)
- glulx_free(str);
+ if (str && str != (uint *)temp_buf)
+ glulx_free(str);
}
} // End of namespace Glulxe
diff --git a/engines/glk/glulxe/vm.cpp b/engines/glk/glulxe/vm.cpp
index 194152ad65..44ea106e69 100644
--- a/engines/glk/glulxe/vm.cpp
+++ b/engines/glk/glulxe/vm.cpp
@@ -26,295 +26,291 @@ namespace Glk {
namespace Glulxe {
void Glulxe::setup_vm() {
- byte buf[4 * 7];
-
- pc = 0; // Clear this, so that error messages are cleaner.
- prevpc = 0;
-
- // Read in all the size constants from the game file header
- stream_char_handler = nullptr;
- stream_unichar_handler = nullptr;
-
- _gameFile.seek(0);
- if (_gameFile.read(buf, 4 * 7) != (4 * 7))
- fatal_error("The game file header is too short.");
-
- ramstart = Read4(buf + 0);
- endgamefile = Read4(buf + 4);
- origendmem = Read4(buf + 8);
- stacksize = Read4(buf + 12);
- startfuncaddr = Read4(buf + 16);
- origstringtable = Read4(buf + 20);
- checksum = Read4(buf + 24);
-
- // Set the protection range to (0, 0), meaning "off".
- protectstart = 0;
- protectend = 0;
-
- // Do a few sanity checks.
- if ((ramstart & 0xFF)
- || (endgamefile & 0xFF)
- || (origendmem & 0xFF)
- || (stacksize & 0xFF)) {
- nonfatal_warning("One of the segment boundaries in the header is not "
- "256-byte aligned.");
- }
-
- if (endgamefile != gamefile_len) {
- nonfatal_warning("The gamefile length does not match the header "
- "endgamefile length.");
- }
-
- if (ramstart < 0x100 || endgamefile < ramstart || origendmem < endgamefile) {
- fatal_error("The segment boundaries in the header are in an impossible "
- "order.");
- }
- if (stacksize < 0x100) {
- fatal_error("The stack size in the header is too small.");
- }
-
- /* Allocate main memory and the stack. This is where memory allocation
- errors are most likely to occur. */
- endmem = origendmem;
- memmap = (byte *)glulx_malloc(origendmem);
- if (!memmap) {
- fatal_error("Unable to allocate Glulx memory space.");
- }
- stack = (byte *)glulx_malloc(stacksize);
- if (!stack) {
- glulx_free(memmap);
- memmap = nullptr;
- fatal_error("Unable to allocate Glulx stack space.");
- }
- stringtable = 0;
-
- // Initialize various other things in the terp.
- init_operands();
- init_serial();
-
- // Set up the initial machine state.
- vm_restart();
-
- /* If the debugger is compiled in, check that the debug data matches
- the game. (This only prints warnings for mismatch.) */
- debugger_check_story_file();
-
- /* Also, set up any start-time debugger state. This may do a block-
- and-debug, if the user has requested that. */
- debugger_setup_start_state();
+ byte buf[4 * 7];
+
+ pc = 0; // Clear this, so that error messages are cleaner.
+ prevpc = 0;
+
+ // Read in all the size constants from the game file header
+ stream_char_handler = nullptr;
+ stream_unichar_handler = nullptr;
+
+ _gameFile.seek(0);
+ if (_gameFile.read(buf, 4 * 7) != (4 * 7))
+ fatal_error("The game file header is too short.");
+
+ ramstart = Read4(buf + 0);
+ endgamefile = Read4(buf + 4);
+ origendmem = Read4(buf + 8);
+ stacksize = Read4(buf + 12);
+ startfuncaddr = Read4(buf + 16);
+ origstringtable = Read4(buf + 20);
+ checksum = Read4(buf + 24);
+
+ // Set the protection range to (0, 0), meaning "off".
+ protectstart = 0;
+ protectend = 0;
+
+ // Do a few sanity checks.
+ if ((ramstart & 0xFF)
+ || (endgamefile & 0xFF)
+ || (origendmem & 0xFF)
+ || (stacksize & 0xFF)) {
+ nonfatal_warning("One of the segment boundaries in the header is not "
+ "256-byte aligned.");
+ }
+
+ if (endgamefile != gamefile_len) {
+ nonfatal_warning("The gamefile length does not match the header "
+ "endgamefile length.");
+ }
+
+ if (ramstart < 0x100 || endgamefile < ramstart || origendmem < endgamefile) {
+ fatal_error("The segment boundaries in the header are in an impossible "
+ "order.");
+ }
+ if (stacksize < 0x100) {
+ fatal_error("The stack size in the header is too small.");
+ }
+
+ /* Allocate main memory and the stack. This is where memory allocation
+ errors are most likely to occur. */
+ endmem = origendmem;
+ memmap = (byte *)glulx_malloc(origendmem);
+ if (!memmap) {
+ fatal_error("Unable to allocate Glulx memory space.");
+ }
+ stack = (byte *)glulx_malloc(stacksize);
+ if (!stack) {
+ glulx_free(memmap);
+ memmap = nullptr;
+ fatal_error("Unable to allocate Glulx stack space.");
+ }
+ stringtable = 0;
+
+ // Initialize various other things in the terp.
+ init_operands();
+ init_serial();
+
+ // Set up the initial machine state.
+ vm_restart();
+
+ /* If the debugger is compiled in, check that the debug data matches
+ the game. (This only prints warnings for mismatch.) */
+ debugger_check_story_file();
+
+ /* Also, set up any start-time debugger state. This may do a block-
+ and-debug, if the user has requested that. */
+ debugger_setup_start_state();
}
void Glulxe::finalize_vm() {
- stream_set_table(0);
-
- if (memmap) {
- glulx_free(memmap);
- memmap = nullptr;
- }
- if (stack) {
- glulx_free(stack);
- stack = nullptr;
- }
-
- final_serial();
+ stream_set_table(0);
+
+ if (memmap) {
+ glulx_free(memmap);
+ memmap = nullptr;
+ }
+ if (stack) {
+ glulx_free(stack);
+ stack = nullptr;
+ }
+
+ final_serial();
}
void Glulxe::vm_restart() {
- uint lx;
- int res;
- int bufpos;
- char buf[0x100];
-
- /* Deactivate the heap (if it was active). */
- heap_clear();
-
- /* Reset memory to the original size. */
- lx = change_memsize(origendmem, false);
- if (lx)
- fatal_error("Memory could not be reset to its original size.");
-
- /* Load in all of main memory. We do this in 256-byte chunks, because
- why rely on OS stream buffering? */
- _gameFile.seek(gamefile_start);
- bufpos = 0x100;
-
- for (lx=0; lx<endgamefile; lx++) {
- if (bufpos >= 0x100) {
- int count = _gameFile.read(buf, 0x100);
- if (count != 0x100) {
- fatal_error("The game file ended unexpectedly.");
- }
- bufpos = 0;
- }
-
- res = buf[bufpos++];
- if (lx >= protectstart && lx < protectend)
- continue;
- memmap[lx] = res;
- }
- for (lx=endgamefile; lx<origendmem; lx++) {
- memmap[lx] = 0;
- }
-
- /* Reset all the registers */
- stackptr = 0;
- frameptr = 0;
- pc = 0;
- prevpc = 0;
- stream_set_iosys(0, 0);
- stream_set_table(origstringtable);
- valstackbase = 0;
- localsbase = 0;
-
- /* Note that we do not reset the protection range. */
-
- /* Push the first function call. (No arguments.) */
- enter_function(startfuncaddr, 0, nullptr);
-
- /* We're now ready to execute. */
+ uint lx;
+ int res;
+ int bufpos;
+ char buf[0x100];
+
+ /* Deactivate the heap (if it was active). */
+ heap_clear();
+
+ /* Reset memory to the original size. */
+ lx = change_memsize(origendmem, false);
+ if (lx)
+ fatal_error("Memory could not be reset to its original size.");
+
+ /* Load in all of main memory. We do this in 256-byte chunks, because
+ why rely on OS stream buffering? */
+ _gameFile.seek(gamefile_start);
+ bufpos = 0x100;
+
+ for (lx = 0; lx < endgamefile; lx++) {
+ if (bufpos >= 0x100) {
+ int count = _gameFile.read(buf, 0x100);
+ if (count != 0x100) {
+ fatal_error("The game file ended unexpectedly.");
+ }
+ bufpos = 0;
+ }
+
+ res = buf[bufpos++];
+ if (lx >= protectstart && lx < protectend)
+ continue;
+ memmap[lx] = res;
+ }
+ for (lx = endgamefile; lx < origendmem; lx++) {
+ memmap[lx] = 0;
+ }
+
+ /* Reset all the registers */
+ stackptr = 0;
+ frameptr = 0;
+ pc = 0;
+ prevpc = 0;
+ stream_set_iosys(0, 0);
+ stream_set_table(origstringtable);
+ valstackbase = 0;
+ localsbase = 0;
+
+ /* Note that we do not reset the protection range. */
+
+ /* Push the first function call. (No arguments.) */
+ enter_function(startfuncaddr, 0, nullptr);
+
+ /* We're now ready to execute. */
}
uint Glulxe::change_memsize(uint newlen, bool internal) {
- uint lx;
- unsigned char *newmemmap;
+ uint lx;
+ unsigned char *newmemmap;
- if (newlen == endmem)
- return 0;
+ if (newlen == endmem)
+ return 0;
#ifdef FIXED_MEMSIZE
- return 1;
+ return 1;
#else /* FIXED_MEMSIZE */
- if ((!internal) && heap_is_active())
- fatal_error("Cannot resize Glulx memory space while heap is active.");
+ if ((!internal) && heap_is_active())
+ fatal_error("Cannot resize Glulx memory space while heap is active.");
- if (newlen < origendmem)
- fatal_error("Cannot resize Glulx memory space smaller than it started.");
+ if (newlen < origendmem)
+ fatal_error("Cannot resize Glulx memory space smaller than it started.");
- if (newlen & 0xFF)
- fatal_error("Can only resize Glulx memory space to a 256-byte boundary.");
-
- newmemmap = (unsigned char *)glulx_realloc(memmap, newlen);
- if (!newmemmap) {
- /* The old block is still in place, unchanged. */
- return 1;
- }
- memmap = newmemmap;
+ if (newlen & 0xFF)
+ fatal_error("Can only resize Glulx memory space to a 256-byte boundary.");
- if (newlen > endmem) {
- for (lx=endmem; lx<newlen; lx++) {
- memmap[lx] = 0;
- }
- }
+ newmemmap = (unsigned char *)glulx_realloc(memmap, newlen);
+ if (!newmemmap) {
+ /* The old block is still in place, unchanged. */
+ return 1;
+ }
+ memmap = newmemmap;
- endmem = newlen;
+ if (newlen > endmem) {
+ for (lx = endmem; lx < newlen; lx++) {
+ memmap[lx] = 0;
+ }
+ }
- return 0;
+ endmem = newlen;
+
+ return 0;
#endif /* FIXED_MEMSIZE */
}
uint *Glulxe::pop_arguments(uint count, uint addr) {
- uint ix;
- uint argptr;
- uint *array;
-
- #define MAXARGS (32)
- static uint statarray[MAXARGS];
- static uint *dynarray = nullptr;
- static uint dynarray_size = 0;
-
- if (count == 0)
- return nullptr;
-
- if (count <= MAXARGS) {
- /* Store in the static array. */
- array = statarray;
- }
- else {
- if (!dynarray) {
- dynarray_size = count+8;
- dynarray = (uint *)glulx_malloc(sizeof(uint) * dynarray_size);
- if (!dynarray)
- fatal_error("Unable to allocate function arguments.");
- array = dynarray;
- }
- else {
- if (dynarray_size >= count) {
- /* It fits. */
- array = dynarray;
- }
- else {
- dynarray_size = count+8;
- dynarray = (uint *)glulx_realloc(dynarray, sizeof(uint) * dynarray_size);
- if (!dynarray)
- fatal_error("Unable to reallocate function arguments.");
- array = dynarray;
- }
- }
- }
-
- if (!addr) {
- if (stackptr < valstackbase+4*count)
- fatal_error("Stack underflow in arguments.");
- stackptr -= 4*count;
- for (ix=0; ix<count; ix++) {
- argptr = stackptr+4*((count-1)-ix);
- array[ix] = Stk4(argptr);
- }
- }
- else {
- for (ix=0; ix<count; ix++) {
- array[ix] = Mem4(addr);
- addr += 4;
- }
- }
-
- return array;
+ uint ix;
+ uint argptr;
+ uint *array;
+
+#define MAXARGS (32)
+ static uint statarray[MAXARGS];
+ static uint *dynarray = nullptr;
+ static uint dynarray_size = 0;
+
+ if (count == 0)
+ return nullptr;
+
+ if (count <= MAXARGS) {
+ /* Store in the static array. */
+ array = statarray;
+ } else {
+ if (!dynarray) {
+ dynarray_size = count + 8;
+ dynarray = (uint *)glulx_malloc(sizeof(uint) * dynarray_size);
+ if (!dynarray)
+ fatal_error("Unable to allocate function arguments.");
+ array = dynarray;
+ } else {
+ if (dynarray_size >= count) {
+ /* It fits. */
+ array = dynarray;
+ } else {
+ dynarray_size = count + 8;
+ dynarray = (uint *)glulx_realloc(dynarray, sizeof(uint) * dynarray_size);
+ if (!dynarray)
+ fatal_error("Unable to reallocate function arguments.");
+ array = dynarray;
+ }
+ }
+ }
+
+ if (!addr) {
+ if (stackptr < valstackbase + 4 * count)
+ fatal_error("Stack underflow in arguments.");
+ stackptr -= 4 * count;
+ for (ix = 0; ix < count; ix++) {
+ argptr = stackptr + 4 * ((count - 1) - ix);
+ array[ix] = Stk4(argptr);
+ }
+ } else {
+ for (ix = 0; ix < count; ix++) {
+ array[ix] = Mem4(addr);
+ addr += 4;
+ }
+ }
+
+ return array;
}
void Glulxe::verify_address(uint addr, uint count) {
- if (addr >= endmem)
- fatal_error_i("Memory access out of range", addr);
- if (count > 1) {
- addr += (count-1);
- if (addr >= endmem)
- fatal_error_i("Memory access out of range", addr);
- }
+ if (addr >= endmem)
+ fatal_error_i("Memory access out of range", addr);
+ if (count > 1) {
+ addr += (count - 1);
+ if (addr >= endmem)
+ fatal_error_i("Memory access out of range", addr);
+ }
}
void Glulxe::verify_address_write(uint addr, uint count) {
- if (addr < ramstart)
- fatal_error_i("Memory write to read-only address", addr);
- if (addr >= endmem)
- fatal_error_i("Memory access out of range", addr);
- if (count > 1) {
- addr += (count-1);
- if (addr >= endmem)
- fatal_error_i("Memory access out of range", addr);
- }
+ if (addr < ramstart)
+ fatal_error_i("Memory write to read-only address", addr);
+ if (addr >= endmem)
+ fatal_error_i("Memory access out of range", addr);
+ if (count > 1) {
+ addr += (count - 1);
+ if (addr >= endmem)
+ fatal_error_i("Memory access out of range", addr);
+ }
}
void Glulxe::verify_array_addresses(uint addr, uint count, uint size) {
- uint bytecount;
- if (addr >= endmem)
- fatal_error_i("Memory access out of range", addr);
-
- if (count == 0)
- return;
- bytecount = count*size;
-
- /* If just multiplying by the element size overflows, we have trouble. */
- if (bytecount < count)
- fatal_error_i("Memory access way too long", addr);
-
- /* If the byte length by itself is too long, or if its end overflows,
- we have trouble. */
- if (bytecount > endmem || addr+bytecount < addr)
- fatal_error_i("Memory access much too long", addr);
- /* The simple length test. */
- if (addr+bytecount > endmem)
- fatal_error_i("Memory access too long", addr);
+ uint bytecount;
+ if (addr >= endmem)
+ fatal_error_i("Memory access out of range", addr);
+
+ if (count == 0)
+ return;
+ bytecount = count * size;
+
+ /* If just multiplying by the element size overflows, we have trouble. */
+ if (bytecount < count)
+ fatal_error_i("Memory access way too long", addr);
+
+ /* If the byte length by itself is too long, or if its end overflows,
+ we have trouble. */
+ if (bytecount > endmem || addr + bytecount < addr)
+ fatal_error_i("Memory access much too long", addr);
+ /* The simple length test. */
+ if (addr + bytecount > endmem)
+ fatal_error_i("Memory access too long", addr);
}
} // End of namespace Glulxe