Beispiel #1
0
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;
}
Beispiel #2
0
/* 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;
}