예제 #1
0
static void
cmd_export(void)
{
   prefix *pfx;

   fExportUsed = fTrue;
   pfx = read_prefix(PFX_STATION);
   do {
      int depth = 0;
      {
	 prefix *p = pfx;
	 while (p != NULL && p != pcs->Prefix) {
	    depth++;
	    p = p->up;
	 }
	 /* Something like: *export \foo, but we've excluded use of root */
	 SVX_ASSERT(p);
      }
      /* *export \ or similar bogus stuff */
      SVX_ASSERT(depth);
#if 0
      printf("C min %d max %d depth %d pfx %s\n",
	     pfx->min_export, pfx->max_export, depth, sprint_prefix(pfx));
#endif
      if (pfx->min_export == 0) {
	 /* not encountered *export for this name before */
	 if (pfx->max_export > depth) report_missing_export(pfx, depth);
	 pfx->min_export = pfx->max_export = depth;
      } else if (pfx->min_export != USHRT_MAX) {
	 /* FIXME: what to do if a station is marked for inferred exports
	  * but is then explicitly exported?  Currently we just ignore the
	  * explicit export... */
	 if (pfx->min_export - 1 > depth) {
	    report_missing_export(pfx, depth);
	 } else if (pfx->min_export - 1 < depth) {
	    compile_error(/*Station “%s” already exported*/66,
			  sprint_prefix(pfx));
	 }
	 pfx->min_export = depth;
      }
      pfx = read_prefix(PFX_STATION|PFX_OPT);
   } while (pfx);
}
예제 #2
0
static void
cmd_equate(void)
{
   prefix *name1, *name2;
   bool fOnlyOneStn = fTrue; /* to trap eg *equate entrance.6 */

   name1 = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO);
   while (fTrue) {
      name2 = name1;
      name1 = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO|PFX_OPT);
      if (name1 == NULL) {
	 if (fOnlyOneStn) {
	    compile_error_skip(-/*Only one station in EQUATE command*/33);
	 }
	 return;
      }

      process_equate(name1, name2);
      fOnlyOneStn = fFalse;
   }
}
예제 #3
0
파일: jfdb.c 프로젝트: jflatow/jfdb
static int prefix_opts(JFT_Stem *prefix, JFT_Symbol **stop, int argc, char **argv) {
  extern char *optarg;
  extern int optind, optopt;
  int opt, ptr, err = 0, omit = 1;

  static struct option options[] = {
    {"null", no_argument, NULL, 'n'},
    {"stop", no_argument, NULL, 's'},
    {"primary", no_argument, NULL, 'p'},
    {"indices", no_argument, NULL, 'i'},
    {}
  };

  // default
  prefix->pre = JFT_SYMBOL_PRIMARY;
  prefix->size = 1;

  while ((opt = getopt_long(argc, argv, "hnspi", options, &ptr)) != -1) {
    switch(opt) {
      case 'h':
        return usage(0);
      case 'n':
        omit = 0;
        break;
      case 's':
        *stop = &null;
        break;
      case 'p':
        prefix->pre = JFT_SYMBOL_PRIMARY;
        prefix->size = 1;
        break;
      case 'i':
        prefix->pre = JFT_SYMBOL_INDICES;
        prefix->size = 1;
        break;
      case ':':
        pwarn("%s: option requires an argument -- %c", argv[0], optopt);
        err++;
        break;
      case '?':
        pwarn("%s: illegal option -- %c", argv[0], optopt);
        err++;
        break;
    }
  }

  read_prefix(prefix, omit, argc - optind, argv + optind);
  return err;
}
예제 #4
0
static void
cmd_prefix(void)
{
   static int prefix_depr_count = 0;
   prefix *tag;
   /* Issue warning first, so "*prefix \" warns first that *prefix is
    * deprecated and then that ROOT is...
    */
   if (prefix_depr_count < 5) {
      compile_warning(-/**prefix is deprecated - use *begin and *end instead*/6);
      if (++prefix_depr_count == 5)
	 compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
   }
   tag = read_prefix(PFX_SURVEY|PFX_ALLOW_ROOT);
   pcs->Prefix = tag;
   check_reentry(tag);
}
예제 #5
0
static void
cmd_begin(void)
{
   prefix *tag;
   settings *pcsNew;

   pcsNew = osnew(settings);
   *pcsNew = *pcs; /* copy contents */
   pcsNew->begin_lineno = file.line;
   pcsNew->next = pcs;
   pcs = pcsNew;

   tag = read_prefix(PFX_SURVEY|PFX_OPT|PFX_ALLOW_ROOT|PFX_WARN_SEPARATOR);
   pcs->tag = tag;
   if (tag) {
      pcs->Prefix = tag;
      check_reentry(tag);
      f_export_ok = fTrue;
   }
}
예제 #6
0
static void
cmd_end(void)
{
   settings *pcsParent;
   prefix *tag, *tagBegin;

   pcsParent = pcs->next;

   if (pcs->begin_lineno == 0) {
      if (pcsParent == NULL) {
	 /* more ENDs than BEGINs */
	 compile_error_skip(/*No matching BEGIN*/192);
      } else {
	 compile_error_skip(/*END with no matching BEGIN in this file*/22);
      }
      return;
   }

   tagBegin = pcs->tag;

   SVX_ASSERT(pcsParent);
   free_settings(pcs);
   pcs = pcsParent;

   /* note need to read using root *before* BEGIN */
   tag = read_prefix(PFX_SURVEY|PFX_OPT|PFX_ALLOW_ROOT);
   if (tag != tagBegin) {
      if (tag) {
	 if (!tagBegin) {
	    /* "*begin" / "*end foo" */
	    compile_error_skip(-/*Matching BEGIN tag has no prefix*/36);
	 } else {
	    /* tag mismatch */
	    compile_error_skip(-/*Prefix tag doesn’t match BEGIN*/193);
	 }
      } else {
	 /* close tag omitted; open tag given */
	 compile_warning(-/*Closing prefix omitted from END*/194);
      }
   }
}
예제 #7
0
파일: glkop.cpp 프로젝트: fingolfin/scummvm
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');
							assert(objrock.ptr);
							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;
#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;
}
예제 #8
0
파일: glkop.cpp 프로젝트: fingolfin/scummvm
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;
#ifdef GLK_MODULE_UNICODE
				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;
}
예제 #9
0
파일: glkop.cpp 프로젝트: fingolfin/scummvm
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
                         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;
}
예제 #10
0
static void
cmd_fix(void)
{
   prefix *fix_name;
   node *stn = NULL;
   static node *stnOmitAlready = NULL;
   real x, y, z;
   int nx, ny, nz;
   filepos fp;

   fix_name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
   fix_name->sflags |= BIT(SFLAGS_FIXED);

   get_pos(&fp);
   get_token();
   if (strcmp(ucbuffer, "REFERENCE") == 0) {
      /* suppress "unused fixed point" warnings for this station */
      fix_name->sflags |= BIT(SFLAGS_USED);
   } else {
      if (*ucbuffer) set_pos(&fp);
   }

   x = read_numeric(fTrue, &nx);
   if (x == HUGE_REAL) {
      /* If the end of the line isn't blank, read a number after all to
       * get a more helpful error message */
      if (!isEol(ch) && !isComm(ch)) x = read_numeric(fFalse, &nx);
   }
   if (x == HUGE_REAL) {
      if (stnOmitAlready) {
	 if (fix_name != stnOmitAlready->name) {
	    compile_error_skip(/*More than one FIX command with no coordinates*/56);
	 } else {
	    compile_warning(/*Same station fixed twice with no coordinates*/61);
	 }
	 return;
      }
      stn = StnFromPfx(fix_name);
      compile_warning(/*FIX command with no coordinates - fixing at (0,0,0)*/54);
      x = y = z = (real)0.0;
      stnOmitAlready = stn;
   } else {
      real sdx;
      y = read_numeric(fFalse, &ny);
      z = read_numeric(fFalse, &nz);
      sdx = read_numeric(fTrue, NULL);
      if (sdx != HUGE_REAL) {
	 real sdy, sdz;
	 real cxy = 0, cyz = 0, czx = 0;
	 sdy = read_numeric(fTrue, NULL);
	 if (sdy == HUGE_REAL) {
	    /* only one variance given */
	    sdy = sdz = sdx;
	 } else {
	    sdz = read_numeric(fTrue, NULL);
	    if (sdz == HUGE_REAL) {
	       /* two variances given - horizontal & vertical */
	       sdz = sdy;
	       sdy = sdx;
	    } else {
	       cxy = read_numeric(fTrue, NULL);
	       if (cxy != HUGE_REAL) {
		  /* covariances given */
		  cyz = read_numeric(fFalse, NULL);
		  czx = read_numeric(fFalse, NULL);
	       } else {
		  cxy = 0;
	       }
	    }
	 }
	 stn = StnFromPfx(fix_name);
	 if (!fixed(stn)) {
	    node *fixpt = osnew(node);
	    prefix *name;
	    name = osnew(prefix);
	    name->pos = osnew(pos);
	    name->ident = NULL;
	    name->shape = 0;
	    fixpt->name = name;
	    name->stn = fixpt;
	    name->up = NULL;
	    if (TSTBIT(pcs->infer, INFER_EXPORTS)) {
	       name->min_export = USHRT_MAX;
	    } else {
	       name->min_export = 0;
	    }
	    name->max_export = 0;
	    name->sflags = 0;
	    add_stn_to_list(&stnlist, fixpt);
	    POS(fixpt, 0) = x;
	    POS(fixpt, 1) = y;
	    POS(fixpt, 2) = z;
	    fix(fixpt);
	    fixpt->leg[0] = fixpt->leg[1] = fixpt->leg[2] = NULL;
	    addfakeleg(fixpt, stn, 0, 0, 0,
		       sdx * sdx, sdy * sdy, sdz * sdz
#ifndef NO_COVARIANCES
		       , cxy, cyz, czx
#endif
		       );
	 }
	 return;
      }
      stn = StnFromPfx(fix_name);
   }

   if (!fixed(stn)) {
      POS(stn, 0) = x;
      POS(stn, 1) = y;
      POS(stn, 2) = z;
      fix(stn);
      return;
   }

   if (x != POS(stn, 0) || y != POS(stn, 1) || z != POS(stn, 2)) {
      compile_error(/*Station already fixed or equated to a fixed point*/46);
      return;
   }
   compile_warning(/*Station already fixed at the same coordinates*/55);
}
예제 #11
0
static void
cmd_entrance(void)
{
   prefix *pfx = read_prefix(PFX_STATION);
   pfx->sflags |= BIT(SFLAGS_ENTRANCE);
}
예제 #12
0
ll read_range(int l, int r) { // get sum v[l..r]
  return read_prefix(r) - read_prefix(l - 1);
}
예제 #13
0
파일: glkop.c 프로젝트: iainmerrick/gift
/* parse_glk_args():
   This long and unpleasant function translates a set of Floo objects into
   a gluniversal_t array. It's recursive, too, to deal with structures.
*/
static void parse_glk_args(dispatch_splot_t *splot, char **proto, int depth,
  int *argnumptr, glui32 subaddress, int subpassin)
{
  char *cx;
  int ix, argx;
  int gargnum, numwanted;
  void *opref;
  gluniversal_t *garglist;
  glui32 *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)
          fatalError("Zero passed invalidly to Glk function.");
        garglist[gargnum].ptrflag = FALSE;
        gargnum++;
        skipval = TRUE;
      }
      else {
        garglist[gargnum].ptrflag = TRUE;
        gargnum++;
      }
    }
    if (!skipval) {
      glui32 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, and cuts it down to
             something reasonable. Future releases of this interpreter may
             treat this case as a fatal error. */
          if (varglist[ix+1] > gEndMem || varglist[ix]+varglist[ix+1] > gEndMem)
            varglist[ix+1] = gEndMem - varglist[ix];

          garglist[gargnum].array = (void*) 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] > gEndMem/4 || varglist[ix+1] > (gEndMem-varglist[ix])/4)
            varglist[ix+1] = (gEndMem - varglist[ix]) / 4;

          garglist[gargnum].array = CaptureIArray(varglist[ix], varglist[ix+1], passin);
          gargnum++;
          ix++;
          garglist[gargnum].uint = varglist[ix];
          gargnum++;
          cx++;
          break;
        case 'Q':
          garglist[gargnum].array = CapturePtrArray(varglist[ix], varglist[ix+1], (*cx-'a'), passin);
          gargnum++;
          ix++;
          garglist[gargnum].uint = varglist[ix];
          gargnum++;
          cx++;
          break;
        default:
          fatalError("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 = (glui32)(thisval);
          else if (*cx == 's')
            garglist[gargnum].sint = (glsi32)(thisval);
          else
            fatalError("Illegal format string.");
          gargnum++;
          cx++;
          break;
        case 'Q':
          if (thisval) {
            opref = classes_get(*cx-'a', thisval);
            if (!opref) {
              fatalError("Reference to nonexistent Glk object.");
            }
          }
          else {
            opref = NULL;
          }
          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
            fatalError("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;
#endif /* GLK_MODULE_UNICODE */
        default:
          fatalError("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 != ']')
      fatalError("Illegal format string.");
    cx++;
  }
  else {
    if (*cx != ':' && *cx != '\0')
      fatalError("Illegal format string.");
  }
  
  *proto = cx;
  *argnumptr = gargnum;
}