Skip to content

Commit a43c6bd

Browse files
author
David Kinder
committed
Add opaque object array handling dispatch fix from Glulxe
1 parent b979664 commit a43c6bd

File tree

7 files changed

+167
-58
lines changed

7 files changed

+167
-58
lines changed

‎README.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ also to Eliuk Blau for tracking down bugs in the memory management opcodes.
192192

193193
* Version History
194194

195+
1.3.0 2011-12-16 Fixed a bug in glkop.c dispatching, to do with arrays
196+
of opaque objects, following a similar fix in Glulxe.
197+
195198
1.2.9 2011-08-28 Fixed a bug in glkop.c dispatching, to do with optional
196199
array arguments, following a similar fix in Glulxe.
197200
Glk array and string operations are now checked for memory

‎git.h‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,8 @@
2121
#define _str2(s) #s
2222
#define _str(s) _str2(s)
2323

24-
#if GIT_PATCH == 0
25-
#define GIT_VERSION_STR \
26-
_str(GIT_MAJOR) "." _str(GIT_MINOR)
27-
#else
2824
#define GIT_VERSION_STR \
2925
_str(GIT_MAJOR) "." _str(GIT_MINOR) "." _str(GIT_PATCH)
30-
#endif
3126

3227
// git.c
3328

‎glkop.c‎

Lines changed: 154 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
These macros are responsible for fixing byte-order and alignment
2525
(if the C ABI does not match the VM's). The passin, passout hints
2626
may be used to avoid unnecessary copying.
27+
- A Glk object array is a sequence of integers in VM memory. It is
28+
turned into a C pointer array (remember that C pointers may be more
29+
than 4 bytes!) The pointer array is allocated by
30+
CapturePtrArray(addr, len, objclass) and released by ReleasePtrArray().
31+
Again, the macros handle the conversion.
2732
- A Glk structure (such as event_t) is a set of integers somewhere
2833
in VM memory, which can be read and written with the macros
2934
ReadStructField(addr, fieldnum) and WriteStructField(addr, fieldnum).
@@ -70,6 +75,10 @@
7075
(grab_temp_array(addr, len, passin))
7176
#define ReleaseIArray(ptr, addr, len, passout) \
7277
(release_temp_array(ptr, addr, len, passout))
78+
#define CapturePtrArray(addr, len, objclass, passin) \
79+
(grab_temp_ptr_array(addr, len, objclass, passin))
80+
#define ReleasePtrArray(ptr, addr, len, objclass, passout) \
81+
(release_temp_ptr_array(ptr, addr, len, objclass, passout))
7382
#define ReadStructField(addr, fieldnum) \
7483
(((addr) == 0xffffffff) \
7584
? (gStackPointer -= 1, Stk4(gStackPointer)) \
@@ -228,6 +237,8 @@ static void glulxe_retained_unregister(void *array, glui32 len,
228237

229238
static glui32 *grab_temp_array(glui32 addr, glui32 len, int passin);
230239
static void release_temp_array(glui32 *arr, glui32 addr, glui32 len, int passout);
240+
static void **grab_temp_ptr_array(glui32 addr, glui32 len, int objclass, int passin);
241+
static void release_temp_ptr_array(void **arr, glui32 addr, glui32 len, int objclass, int passout);
231242

232243
static void prepare_glk_args(char *proto, dispatch_splot_t *splot);
233244
static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
@@ -277,16 +288,16 @@ glui32 git_perform_glk(glui32 funcnum, glui32 numargs, glui32 *arglist)
277288
directly -- instead of bothering with the whole prototype
278289
mess. */
279290

280-
case 0x0047: /* stream_set_current */
281-
if (numargs != 1)
282-
goto WrongArgNum;
283-
glk_stream_set_current(git_find_stream_by_id(arglist[0]));
284-
break;
285-
case 0x0048: /* stream_get_current */
286-
if (numargs != 0)
287-
goto WrongArgNum;
288-
retval = git_find_id_for_stream(glk_stream_get_current());
289-
break;
291+
case 0x0047: /* stream_set_current */
292+
if (numargs != 1)
293+
goto WrongArgNum;
294+
glk_stream_set_current(git_find_stream_by_id(arglist[0]));
295+
break;
296+
case 0x0048: /* stream_get_current */
297+
if (numargs != 0)
298+
goto WrongArgNum;
299+
retval = git_find_id_for_stream(glk_stream_get_current());
300+
break;
290301
case 0x0080: /* put_char */
291302
if (numargs != 1)
292303
goto WrongArgNum;
@@ -307,16 +318,16 @@ glui32 git_perform_glk(glui32 funcnum, glui32 numargs, glui32 *arglist)
307318
goto WrongArgNum;
308319
retval = glk_char_to_upper(arglist[0] & 0xFF);
309320
break;
310-
case 0x0128: /* put_char_uni */
311-
if (numargs != 1)
312-
goto WrongArgNum;
313-
glk_put_char_uni(arglist[0]);
314-
break;
315-
case 0x012B: /* put_char_stream_uni */
316-
if (numargs != 2)
317-
goto WrongArgNum;
318-
glk_put_char_stream_uni(git_find_stream_by_id(arglist[0]), arglist[1]);
319-
break;
321+
case 0x0128: /* put_char_uni */
322+
if (numargs != 1)
323+
goto WrongArgNum;
324+
glk_put_char_uni(arglist[0]);
325+
break;
326+
case 0x012B: /* put_char_stream_uni */
327+
if (numargs != 2)
328+
goto WrongArgNum;
329+
glk_put_char_stream_uni(git_find_stream_by_id(arglist[0]), arglist[1]);
330+
break;
320331

321332
WrongArgNum:
322333
fatalError("Wrong number of arguments to Glk function.");
@@ -355,11 +366,11 @@ glui32 git_perform_glk(glui32 funcnum, glui32 numargs, glui32 *arglist)
355366
gidispatch_call(funcnum, argnum, splot.garglist);
356367

357368
/* Phase 3. */
358-
argnum2 = 0;
369+
argnum2 = 0;
359370
cx = proto;
360371
unparse_glk_args(&splot, &cx, 0, &argnum2, 0, 0);
361-
if (argnum != argnum2)
362-
fatalError("Argument counts did not match.");
372+
if (argnum != argnum2)
373+
fatalError("Argument counts did not match.");
363374

364375
break;
365376
}
@@ -582,11 +593,11 @@ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
582593

583594
switch (typeclass) {
584595
case 'C':
585-
/* This test checks for a giant array length, and cuts it down to
586-
something reasonable. Future releases of this interpreter may
587-
treat this case as a fatal error. */
588-
if (varglist[ix+1] > gEndMem || varglist[ix]+varglist[ix+1] > gEndMem)
589-
varglist[ix+1] = gEndMem - varglist[ix];
596+
/* This test checks for a giant array length, and cuts it down to
597+
something reasonable. Future releases of this interpreter may
598+
treat this case as a fatal error. */
599+
if (varglist[ix+1] > gEndMem || varglist[ix]+varglist[ix+1] > gEndMem)
600+
varglist[ix+1] = gEndMem - varglist[ix];
590601

591602
garglist[gargnum].array = (void*) AddressOfArray(varglist[ix]);
592603
gargnum++;
@@ -596,9 +607,9 @@ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
596607
cx++;
597608
break;
598609
case 'I':
599-
/* See comment above. */
600-
if (varglist[ix+1] > gEndMem/4 || varglist[ix+1] > (gEndMem-varglist[ix])/4)
601-
varglist[ix+1] = (gEndMem - varglist[ix]) / 4;
610+
/* See comment above. */
611+
if (varglist[ix+1] > gEndMem/4 || varglist[ix+1] > (gEndMem-varglist[ix])/4)
612+
varglist[ix+1] = (gEndMem - varglist[ix]) / 4;
602613

603614
garglist[gargnum].array = CaptureIArray(varglist[ix], varglist[ix+1], passin);
604615
gargnum++;
@@ -607,6 +618,16 @@ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
607618
gargnum++;
608619
cx++;
609620
break;
621+
case 'Q':
622+
/* This case was added after the giant arrays were deprecated,
623+
so we don't bother to allow for that case. */
624+
garglist[gargnum].array = CapturePtrArray(varglist[ix], varglist[ix+1], (*cx-'a'), passin);
625+
gargnum++;
626+
ix++;
627+
garglist[gargnum].uint = varglist[ix];
628+
gargnum++;
629+
cx++;
630+
break;
610631
default:
611632
fatalError("Illegal format string.");
612633
break;
@@ -711,8 +732,8 @@ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
711732
}
712733
else {
713734
cx++;
714-
if (isarray)
715-
ix++;
735+
if (isarray)
736+
ix++;
716737
}
717738
}
718739
}
@@ -804,6 +825,13 @@ static void unparse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
804825
gargnum++;
805826
cx++;
806827
break;
828+
case 'Q':
829+
ReleasePtrArray(garglist[gargnum].array, varglist[ix], varglist[ix+1], (*cx-'a'), passout);
830+
gargnum++;
831+
ix++;
832+
gargnum++;
833+
cx++;
834+
break;
807835
default:
808836
fatalError("Illegal format string.");
809837
break;
@@ -919,8 +947,8 @@ static void unparse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
919947
}
920948
else {
921949
cx++;
922-
if (isarray)
923-
ix++;
950+
if (isarray)
951+
ix++;
924952
}
925953
}
926954
}
@@ -952,20 +980,20 @@ strid_t git_find_stream_by_id(glui32 objid)
952980
return classes_get(1, objid);
953981
}
954982

955-
/* find_id_for_stream():
956-
The converse of find_stream_by_id().
957-
This is only needed in this file, so it's static.
958-
*/
959-
glui32 git_find_id_for_stream(strid_t str)
960-
{
961-
gidispatch_rock_t objrock;
962-
963-
if (!str)
964-
return 0;
965-
966-
objrock = gidispatch_get_objrock(str, 1);
967-
return ((classref_t *)objrock.ptr)->id;
968-
}
983+
/* find_id_for_stream():
984+
The converse of find_stream_by_id().
985+
This is only needed in this file, so it's static.
986+
*/
987+
glui32 git_find_id_for_stream(strid_t str)
988+
{
989+
gidispatch_rock_t objrock;
990+
991+
if (!str)
992+
return 0;
993+
994+
objrock = gidispatch_get_objrock(str, 1);
995+
return ((classref_t *)objrock.ptr)->id;
996+
}
969997

970998
/* Build a hash table to hold a set of Glk objects. */
971999
static classtable_t *new_classtable(glui32 firstid)
@@ -1136,6 +1164,83 @@ static void release_temp_array(glui32 *arr, glui32 addr, glui32 len, int passout
11361164
}
11371165
}
11381166

1167+
static void **grab_temp_ptr_array(glui32 addr, glui32 len, int objclass, int passin)
1168+
{
1169+
arrayref_t *arref = NULL;
1170+
void **arr = NULL;
1171+
glui32 ix, addr2;
1172+
1173+
if (len) {
1174+
arr = (void **)glulx_malloc(len * sizeof(void *));
1175+
arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
1176+
if (!arr || !arref)
1177+
fatalError("Unable to allocate space for array argument to Glk call.");
1178+
1179+
arref->array = arr;
1180+
arref->addr = addr;
1181+
arref->elemsize = sizeof(void *);
1182+
arref->retained = FALSE;
1183+
arref->len = len;
1184+
arref->next = arrays;
1185+
arrays = arref;
1186+
1187+
if (passin) {
1188+
for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
1189+
glui32 thisval = memRead32(addr2);
1190+
if (thisval)
1191+
arr[ix] = classes_get(objclass, thisval);
1192+
else
1193+
arr[ix] = NULL;
1194+
}
1195+
}
1196+
}
1197+
1198+
return arr;
1199+
}
1200+
1201+
static void release_temp_ptr_array(void **arr, glui32 addr, glui32 len, int objclass, int passout)
1202+
{
1203+
arrayref_t *arref = NULL;
1204+
arrayref_t **aptr;
1205+
glui32 ix, val, addr2;
1206+
1207+
if (arr) {
1208+
for (aptr=(&arrays); (*aptr); aptr=(&((*aptr)->next))) {
1209+
if ((*aptr)->array == arr)
1210+
break;
1211+
}
1212+
arref = *aptr;
1213+
if (!arref)
1214+
fatalError("Unable to re-find array argument in Glk call.");
1215+
if (arref->addr != addr || arref->len != len)
1216+
fatalError("Mismatched array argument in Glk call.");
1217+
1218+
if (arref->retained) {
1219+
return;
1220+
}
1221+
1222+
*aptr = arref->next;
1223+
arref->next = NULL;
1224+
1225+
if (passout) {
1226+
for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
1227+
void *opref = arr[ix];
1228+
if (opref) {
1229+
gidispatch_rock_t objrock =
1230+
gidispatch_get_objrock(opref, objclass);
1231+
val = ((classref_t *)objrock.ptr)->id;
1232+
}
1233+
else {
1234+
val = 0;
1235+
}
1236+
memWrite32(addr2, val);
1237+
}
1238+
}
1239+
glulx_free(arr);
1240+
glulx_free(arref);
1241+
}
1242+
}
1243+
11391244
gidispatch_rock_t glulxe_retained_register(void *array,
11401245
glui32 len, char *typecode)
11411246
{

‎help/glulx.htm‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h1>Glulx</h1>
1010
the Inform compiler could compile to, without the limitations of its original output format, Infocom's
1111
Z-Machine.
1212
<p>
13-
Windows Git is based on Iain Merrick's Git 1.2.9, which is a complete implementation of version 3.1.2
13+
Windows Git is based on Iain Merrick's Git 1.3.0, which is a complete implementation of version 3.1.2
1414
of the Glulx specification.
1515
<p>
1616
More information on Glulx is available from the Glulx web page:

‎help/overview.htm‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<link rel="stylesheet" type="text/css" href="Git.css">
55
</head>
66
<body>
7-
<h1>Windows Git 1.2.9<br><font size="-1">(Windows Glk 1.43)</font></h1>
7+
<h1>Windows Git 1.3.0<br><font size="-1">(Windows Glk 1.43)</font></h1>
88
Windows Git is an interpreter for <a href="glulx.htm">Glulx</a> games. Windows Git
99
consists of a core interpreter called Git, and an input/output library, called Windows
1010
Glk. Together these two components form the Windows Git package, which has been created

‎help/revision.htm‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
<body>
77
<h1>Revision History</h1>
88

9+
<b>Git 1.3.0 (Windows Glk 1.43)</b>
10+
<ul>
11+
<li>Updated to Git 1.3.0, which fixes a bug related to Glk call dispatching,
12+
following a similar fix in Glulxe.
13+
</ul>
14+
915
<b>Git 1.2.9 (Windows Glk 1.43)</b>
1016
<ul>
1117
<li>Updated to support Glk 0.7.3, which includes more control when playing sounds.

‎version.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Automatically generated file -- do not edit!
22
#define GIT_MAJOR 1
3-
#define GIT_MINOR 2
4-
#define GIT_PATCH 9
3+
#define GIT_MINOR 3
4+
#define GIT_PATCH 0

0 commit comments

Comments
 (0)