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).
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
229238static glui32 * grab_temp_array (glui32 addr , glui32 len , int passin );
230239static 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
232243static void prepare_glk_args (char * proto , dispatch_splot_t * splot );
233244static 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. */
971999static 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+
11391244gidispatch_rock_t glulxe_retained_register (void * array ,
11401245 glui32 len , char * typecode )
11411246{
0 commit comments