Update Glulxe to 0.4.7
[projects/chimara/chimara.git] / interpreters / glulxe / glkop.c
index e9c519128b29d15d6ca3699433d4b814b4519c4b..090632abdcbfabf5cb6ba83e6662b094723b34ac 100644 (file)
@@ -120,6 +120,8 @@ typedef struct classtable_struct {
 static int num_classes = 0;
 classtable_t **classes = NULL;
 
+static glui32 find_id_for_stream(strid_t str);
+
 static classtable_t *new_classtable(glui32 firstid);
 static void *classes_get(int classid, glui32 objid);
 static classref_t *classes_put(int classid, void *obj);
@@ -185,6 +187,16 @@ glui32 perform_glk(glui32 funcnum, glui32 numargs, glui32 *arglist)
        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;
@@ -205,6 +217,16 @@ glui32 perform_glk(glui32 funcnum, glui32 numargs, glui32 *arglist)
       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:
     fatal_error("Wrong number of arguments to Glk function.");
@@ -214,7 +236,7 @@ glui32 perform_glk(glui32 funcnum, glui32 numargs, glui32 *arglist)
     /* Go through the full dispatcher prototype foo. */
     char *proto, *cx;
     dispatch_splot_t splot;
-    int argnum;
+    int argnum, argnum2;
 
     /* Grab the string. */
     proto = gidispatch_prototype(funcnum);
@@ -243,9 +265,11 @@ glui32 perform_glk(glui32 funcnum, glui32 numargs, glui32 *arglist)
     gidispatch_call(funcnum, argnum, splot.garglist);
 
     /* Phase 3. */
-    argnum = 0;
+    argnum2 = 0;
     cx = proto;
-    unparse_glk_args(&splot, &cx, 0, &argnum, 0, 0);
+    unparse_glk_args(&splot, &cx, 0, &argnum2, 0, 0);
+    if (argnum != argnum2)
+      fatal_error("Argument counts did not match.");
 
     break;
   }
@@ -468,6 +492,17 @@ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
 
         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 = AddressOfArray(varglist[ix]);
           gargnum++;
           ix++;
@@ -476,6 +511,13 @@ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
           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++;
@@ -587,6 +629,8 @@ static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
       }
       else {
         cx++;
+        if (isarray)
+          ix++;
       }
     }    
   }
@@ -789,6 +833,8 @@ static void unparse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
       }
       else {
         cx++;
+        if (isarray)
+          ix++;
       }
     }    
   }
@@ -820,6 +866,21 @@ strid_t find_stream_by_id(glui32 objid)
   return classes_get(1, objid);
 }
 
+/* find_id_for_stream():
+   The converse of find_stream_by_id(). 
+   This is only needed in this file, so it's static.
+*/
+static glui32 find_id_for_stream(strid_t str)
+{
+  gidispatch_rock_t objrock;
+
+  if (!str)
+    return 0;
+
+  objrock = gidispatch_get_objrock(str, 1);
+  return ((classref_t *)objrock.ptr)->id;
+}
+
 /* Build a hash table to hold a set of Glk objects. */
 static classtable_t *new_classtable(glui32 firstid)
 {