Example #1
0
uint *Glulxe::grab_temp_i_array(uint addr, uint len, int passin) {
	arrayref_t *arref = nullptr;
	uint *arr = nullptr;
	uint ix, addr2;

	if (len) {
		arr = (uint *)glulx_malloc(len * sizeof(uint));
		arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
		if (!arr || !arref)
			error("Unable to allocate space for array argument to Glk call.");

		arref->array = arr;
		arref->addr = addr;
		arref->elemsize = 4;
		arref->retained = false;
		arref->len = len;
		arref->next = arrays;
		arrays = arref;

		if (passin) {
			for (ix = 0, addr2 = addr; ix < len; ix++, addr2 += 4) {
				arr[ix] = Mem4(addr2);
			}
		}
	}

	return arr;
}
Example #2
0
void profile_in(glui32 addr, glui32 stackuse, int accel)
{
  frame_t *fra;
  function_t *func;
  struct timeval now;

  if (!profiling_active)
    return;

  /* printf("### IN: %lx%s\n", addr, (accel?" accel":"")); */

  if (profiling_call_counts && current_frame) {
    function_t *parfunc = current_frame->func;
    callcount_t **ccref;
    for (ccref = &parfunc->outcalls; *ccref; ccref = &((*ccref)->next)) {
      if ((*ccref)->toaddr == addr) 
        break;
    }
    if (*ccref) {
      (*ccref)->count += 1;
    }
    else {
      *ccref = glulx_malloc(sizeof(callcount_t));
      (*ccref)->toaddr = addr;
      (*ccref)->count = 1;
      (*ccref)->next = NULL;
    }
  }

  gettimeofday(&now, NULL);

  func = get_function(addr);
  func->call_count += 1;
  if (accel)
    func->accel_count += 1;
  if (!func->entry_depth) {
    func->entry_start_time = now;
    func->entry_start_op = profile_opcount;
  }
  func->entry_depth += 1;

  if (func->max_stack_use < stackuse)
    func->max_stack_use = stackuse;

  fra = (frame_t *)glulx_malloc(sizeof(frame_t));
  if (!fra)
    fatal_error("Profiler: cannot malloc frame.");
  memset(fra, 0, sizeof(frame_t));

  fra->parent = current_frame;
  current_frame = fra;

  if (fra->parent)
    fra->depth = fra->parent->depth + 1;
  fra->func = func;
  fra->entry_time = now;
  fra->entry_op = profile_opcount;
  timerclear(&fra->children_time);
  fra->children_ops = 0;
}
Example #3
0
static glui32 *grab_temp_i_array(glui32 addr, glui32 len, int passin)
{
  arrayref_t *arref = NULL;
  glui32 *arr = NULL;
  glui32 ix, addr2;

  if (len) {
    arr = (glui32 *)glulx_malloc(len * sizeof(glui32));
    arref = (arrayref_t *)glulx_malloc(sizeof(arrayref_t));
    if (!arr || !arref) 
      fatalError("Unable to allocate space for array argument to Glk call.");

    arref->array = arr;
    arref->addr = addr;
    arref->elemsize = 4;
    arref->retained = FALSE;
    arref->len = len;
    arref->next = arrays;
    arrays = arref;

    if (passin) {
      for (ix=0, addr2=addr; ix<len; ix++, addr2+=4) {
        arr[ix] = memRead32(addr2);
      }
    }
  }

  return arr;
}
Example #4
0
static char * DecodeVMString (git_uint32 addr)
{
    glui32 end;
    char * data;
    char * c;
    
    // The string must be a C string.
    if (memRead8(addr) != 0xE0)
    {
        fatalError ("Illegal string type passed to Glk function");
    }
    addr += 1;
    
    end = addr;
    while (memRead8(end) != 0)
        ++end;
    
    data = glulx_malloc (end - addr + 1);
    if (data == NULL)
        fatalError ("Couldn't allocate string");

    c = data;
    while (addr < end)
        *c++ = memRead8(addr++);
    *c = 0;
    
    return data;
}
Example #5
0
/* heap_get_summary():
   Create an array of words, in the VM serialization format:

     heap_start
     alloc_count
     addr of first block
     len of first block
     ...

   (Note that these are glui32 values -- native byte ordering. Also,
   the blocks will be in address order, which is a stricter guarantee
   than the VM specifies; that'll help in heap_apply_summary().)

   If the heap is inactive, store NULL. Return 0 for success;
   otherwise, the operation failed.

   The array returned in summary must be freed with glulx_free() after
   the caller uses it.
*/
int heap_get_summary(glui32 *valcount, glui32 **summary)
{
    glui32 *arr, len, pos;
    heapblock_t *blo;

    *valcount = 0;
    *summary = NULL;

    if (heap_start == 0)
        return 0;

    len = 2 + 2*alloc_count;
    arr = glulx_malloc(len * sizeof(glui32));
    if (!arr)
        return 1;

    pos = 0;
    arr[pos++] = heap_start;
    arr[pos++] = alloc_count;

    for (blo = heap_head; blo; blo = blo->next) {
        if (blo->isfree)
            continue;
        arr[pos++] = blo->addr;
        arr[pos++] = blo->len;
    }

    if (pos != len)
        fatalError("Wrong number of active blocks in heap");

    *valcount = len;
    *summary = arr;
    return 0;
}
Example #6
0
classref_t *Glulxe::classes_put(int classid, void *obj, uint origid) {
	int bucknum;
	classtable_t *ctab;
	classref_t *cref;
	if (classid < 0 || classid >= num_classes)
		return nullptr;
	ctab = classes[classid];
	cref = (classref_t *)glulx_malloc(sizeof(classref_t));
	if (!cref)
		return nullptr;
	cref->obj = obj;
	if (!origid) {
		cref->id = ctab->lastid;
		ctab->lastid++;
	} else {
		cref->id = origid;
		if (ctab->lastid <= origid)
			ctab->lastid = origid + 1;
	}
	bucknum = cref->id % CLASSHASH_SIZE;
	cref->bucknum = bucknum;
	cref->next = ctab->bucket[bucknum];
	ctab->bucket[bucknum] = cref;
	return cref;
}
Example #7
0
bool Glulxe::init_dispatch() {
	int ix;

	/* Set up the game-ID hook. (This is ifdeffed because not all Glk
	   libraries have this call.) */
#ifdef GI_DISPA_GAME_ID_AVAILABLE
	gidispatch_set_game_id_hook(&get_game_id);
#endif /* GI_DISPA_GAME_ID_AVAILABLE */

	/* Allocate the class hash tables. */
	num_classes = gidispatch_count_classes();
	classes = (classtable_t **)glulx_malloc(num_classes  * sizeof(classtable_t *));
	if (!classes)
		return false;

	for (ix = 0; ix < num_classes; ix++) {
		classes[ix] = new_classtable((glulx_random() % (uint)(101)) + 1);
		if (!classes[ix])
			return false;
	}

	/* Set up the two callbacks. */
	gidispatch_set_object_registry(&classtable_register, &classtable_unregister);
	gidispatch_set_retained_registry(&retained_register, &retained_unregister);

	/* If the library supports autorestore callbacks, set those up too.
	   (These are only used in iosglk, currently.) */
#ifdef GIDISPATCH_AUTORESTORE_REGISTRY
	gidispatch_set_autorestore_registry(&glulxe_array_locate, &glulxe_array_restore);
#endif /* GIDISPATCH_AUTORESTORE_REGISTRY */

	return true;
}
Example #8
0
static glui32 * DecodeVMUstring (git_uint32 addr)
{
    glui32 end;
    glui32 * data;
    glui32 * c;
    
    // The string must be a Unicode string.
    if (memRead8(addr) != 0xE2)
    {
        fatalError ("Illegal string type passed to Glk function");
    }
    addr += 4;
    
    end = addr;
    while (memRead32(end) != 0)
        end += 4;
    
    data = glulx_malloc (end - addr + 4);
    if (data == NULL)
        fatalError ("Couldn't allocate string");

    c = data;
    while (addr < end)
    {
        *c++ = memRead32(addr);
        addr += 4;
    }
    *c = 0;
    
    return data;
}
Example #9
0
static function_t *get_function(glui32 addr)
{
  int bucknum = (addr % FUNC_HASH_SIZE);
  function_t *func;

  for (func = (functions[bucknum]); 
       func && func->addr != addr;
       func = func->hash_next) { }

  if (!func) {
    func = (function_t *)glulx_malloc(sizeof(function_t));
    if (!func)
      fatal_error("Profiler: cannot malloc function.");
    memset(func, 0, sizeof(function_t));
    func->hash_next = functions[bucknum];
    functions[bucknum] = func;

    func->addr = addr;
    func->call_count = 0;
    func->accel_count = 0;
    timerclear(&func->entry_start_time);
    func->entry_start_op = 0;
    timerclear(&func->total_time);
    func->total_ops = 0;
    timerclear(&func->self_time);
    func->self_ops = 0;
  }

  return func;
}
Example #10
0
void profile_in(glui32 addr, int accel)
{
  frame_t *fra;
  function_t *func;
  struct timeval now;

  /* printf("### IN: %lx%s\n", addr, (accel?" accel":"")); */

  gettimeofday(&now, NULL);

  func = get_function(addr);
  func->call_count += 1;
  if (accel)
    func->accel_count += 1;
  if (!func->entry_depth) {
    func->entry_start_time = now;
    func->entry_start_op = profile_opcount;
  }
  func->entry_depth += 1;

  fra = (frame_t *)glulx_malloc(sizeof(frame_t));
  if (!fra)
    fatal_error("Profiler: cannot malloc frame.");
  memset(fra, 0, sizeof(frame_t));

  fra->parent = current_frame;
  current_frame = fra;

  fra->func = func;
  fra->entry_time = now;
  fra->entry_op = profile_opcount;
  timerclear(&fra->children_time);
  fra->children_ops = 0;
}
Example #11
0
void accel_set_func(glui32 index, glui32 addr)
{
    int bucknum;
    accelentry_t *ptr;
    int functype;
    acceleration_func new_func = NULL;

    /* Check the Glulx type identifier byte. */
    functype = Mem1(addr);
    if (functype != 0xC0 && functype != 0xC1) {
        fatal_error_i("Attempt to accelerate non-function.", addr);
    }

    if (!accelentries) {
        accelentries = (accelentry_t **)glulx_malloc(ACCEL_HASH_SIZE
                       * sizeof(accelentry_t *));
        if (!accelentries)
            fatal_error("Cannot malloc acceleration table.");
        for (bucknum=0; bucknum<ACCEL_HASH_SIZE; bucknum++)
            accelentries[bucknum] = NULL;
    }

    new_func = accel_find_func(index);
    /* Might be NULL, if the index is zero or not recognized. */

    bucknum = (addr % ACCEL_HASH_SIZE);
    for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
        if (ptr->addr == addr)
            break;
    }
    if (!ptr) {
        if (!new_func) {
            return; /* no need for a new entry */
        }
        ptr = (accelentry_t *)glulx_malloc(sizeof(accelentry_t));
        if (!ptr)
            fatal_error("Cannot malloc acceleration entry.");
        ptr->addr = addr;
        ptr->index = 0;
        ptr->func = NULL;
        ptr->next = accelentries[bucknum];
        accelentries[bucknum] = ptr;
    }

    ptr->index = index;
    ptr->func = new_func;
}
Example #12
0
static glui32 read_heapstate(dest_t *dest, glui32 chunklen, int portable,
  glui32 *sumlen, glui32 **summary)
{
  glui32 res, count, lx;
  glui32 *arr;

  *sumlen = 0;
  *summary = NULL;

  if (chunklen == 0)
    return 0; /* no heap */

  if (!portable) {
    count = chunklen / sizeof(glui32);

    arr = glulx_malloc(chunklen);
    if (!arr)
      return 1;

    res = read_buffer(dest, (void *)arr, chunklen);
    if (res)
      return res;

    *sumlen = count;
    *summary = arr;

    return 0;
  }

  count = chunklen / 4;

  arr = glulx_malloc(count * sizeof(glui32));
  if (!arr)
    return 1;
  
  for (lx=0; lx<count; lx++) {
    res = read_long(dest, arr+lx);
    if (res)
      return res;
  }

  *sumlen = count;
  *summary = arr;

  return 0;
}
Example #13
0
/* init_serial():
   Set up the undo chain and anything else that needs to be set up.
*/
int init_serial()
{
  undo_chain_num = 0;
  undo_chain_size = max_undo_level;
  undo_chain = (unsigned char **)glulx_malloc(sizeof(unsigned char *) * undo_chain_size);
  if (!undo_chain)
    return FALSE;

  return TRUE;
}
Example #14
0
classtable_t *Glulxe::new_classtable(uint firstid) {
	int ix;
	classtable_t *ctab = (classtable_t *)glulx_malloc(sizeof(classtable_t));
	if (!ctab)
		return nullptr;

	for (ix = 0; ix < CLASSHASH_SIZE; ix++)
		ctab->bucket[ix] = nullptr;

	ctab->lastid = firstid;

	return ctab;
}
Example #15
0
/* Build a hash table to hold a set of Glk objects. */
static classtable_t *new_classtable(glui32 firstid)
{
  int ix;
  classtable_t *ctab = (classtable_t *)glulx_malloc(sizeof(classtable_t));
  if (!ctab)
    return NULL;
    
  for (ix=0; ix<CLASSHASH_SIZE; ix++)
    ctab->bucket[ix] = NULL;
    
  ctab->lastid = firstid;
    
  return ctab;
}
Example #16
0
int init_profile()
{
  int bucknum;

  functions = (function_t **)glulx_malloc(FUNC_HASH_SIZE
    * sizeof(function_t *));
  if (!functions) 
    return FALSE;

  for (bucknum=0; bucknum<FUNC_HASH_SIZE; bucknum++) 
    functions[bucknum] = NULL;

  return TRUE;
}
Example #17
0
/* init_serial():
   Set up the undo chain and anything else that needs to be set up.
*/
int init_serial()
{
  undo_chain_num = 0;
  undo_chain_size = max_undo_level;
  undo_chain = (unsigned char **)glulx_malloc(sizeof(unsigned char *) * undo_chain_size);
  if (!undo_chain)
    return FALSE;

#ifdef SERIALIZE_CACHE_RAM
  {
    glui32 len = (endmem - ramstart);
    glui32 res;
    ramcache = (unsigned char *)glulx_malloc(sizeof(unsigned char *) * len);
    if (!ramcache)
      return FALSE;
    glk_stream_set_position(gamefile, gamefile_start+ramstart, seekmode_Start);
    res = glk_get_buffer_stream(gamefile, (char *)ramcache, len);
    if (res != len)
      return FALSE;
  }
#endif /* SERIALIZE_CACHE_RAM */

  return TRUE;
}
Example #18
0
/* git_init_dispatch():
   Set up the class hash tables and other startup-time stuff.
*/
int git_init_dispatch()
{
  int ix;
  
  /* What with one thing and another, this *could* be called more than
     once. We only need to allocate the tables once. */
  if (git_classes)
      return TRUE;
  
  /* Set up the game-ID hook. (This is ifdeffed because not all Glk
     libraries have this call.) */
#ifdef GI_DISPA_GAME_ID_AVAILABLE
  gidispatch_set_game_id_hook(&get_game_id);
#endif /* GI_DISPA_GAME_ID_AVAILABLE */
    
  /* Allocate the class hash tables. */
  num_classes = gidispatch_count_classes();
  git_classes = (classtable_t **)glulx_malloc(num_classes 
    * sizeof(classtable_t *));
  if (!git_classes)
    return FALSE;
    
  for (ix=0; ix<num_classes; ix++) {
    git_classes[ix] = new_classtable((glulx_random() % (glui32)(101)) + 1);
    if (!git_classes[ix])
      return FALSE;
  }
    
  /* Set up the two callbacks. */
  gidispatch_set_object_registry(&glulxe_classtable_register, 
    &glulxe_classtable_unregister);
  gidispatch_set_retained_registry(&glulxe_retained_register, 
    &glulxe_retained_unregister);
  
  return TRUE;
}
Example #19
0
static int write_buffer(dest_t *dest, unsigned char *ptr, glui32 len)
{
  if (dest->ismem) {
    if (dest->pos+len > dest->size) {
      dest->size = dest->pos+len+1024;
      if (!dest->ptr) {
        dest->ptr = glulx_malloc(dest->size);
      }
      else {
        dest->ptr = glulx_realloc(dest->ptr, dest->size);
      }
      if (!dest->ptr)
        return 1;
    }
    memcpy(dest->ptr+dest->pos, ptr, len);
  }
  else {
    glk_put_buffer_stream(dest->str, (char *)ptr, len);
  }

  dest->pos += len;

  return 0;
}
Example #20
0
/* heap_apply_summary():
   Given an array of words in the above format, set up the heap to
   contain it. As noted above, the caller must ensure that the blocks
   are in address order. When this is called, the heap must be
   inactive.

   Return 0 for success. Otherwise the operation failed (and, most
   likely, caused a fatal error).
*/
int heap_apply_summary(glui32 valcount, glui32 *summary)
{
    glui32 lx, jx, lastend;

    if (heap_start)
        fatalError("Heap active when heap_apply_summary called");

    if (valcount == 0 || summary == NULL)
        return 0;
    if (valcount == 2 && summary[0] == 0 && summary[1] == 0)
        return 0;

    lx = 0;
    heap_start = summary[lx++];
    alloc_count = summary[lx++];

    for (jx=lx; jx+2<valcount; jx+=2) {
        if (summary[jx] >= summary[jx+2])
            fatalError("Heap block summary is out of order.");
    }

    lastend = heap_start;

    while (lx < valcount || lastend < gEndMem) {
        heapblock_t *blo;

        blo = glulx_malloc(sizeof(heapblock_t));
        if (!blo)
            fatalError("Unable to allocate record for heap block.");

        if (lx >= valcount) {
            blo->addr = lastend;
            blo->len = gEndMem - lastend;
            blo->isfree = TRUE;
        }
        else {
            if (lastend < summary[lx]) {
                blo->addr = lastend;
                blo->len = summary[lx] - lastend;
                blo->isfree = TRUE;
            }
            else {
                blo->addr = summary[lx++];
                blo->len = summary[lx++];
                blo->isfree = FALSE;
            }
        }

        blo->prev = NULL;
        blo->next = NULL;

        if (!heap_head) {
            heap_head = blo;
            heap_tail = blo;
        }
        else {
            heap_tail->next = blo;
            blo->prev = heap_tail;
            heap_tail = blo;
        }

        lastend = blo->addr + blo->len;
    }

    /* heap_sanity_check(); */

    return 0;
}
Example #21
0
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;
}
Example #22
0
static glui32 classes_iter(glk_object_save_t **objs)
{
    classtable_t *ctab;
    classref_t *cref;
    glui32 num_classes;
    glui32 i,j,ct = 0;
    glk_object_save_t *o = NULL, *cur;

    window_t  *win;
    stream_t *str_cur = glk_stream_get_current();

    if (!objs)
        return 0;

    *objs = NULL;

    num_classes = gidispatch_count_classes();
    ct = 0;
    for (i = 0; i < num_classes; i++) { // iterate everything quickly
        if ((ctab = classes[i])) {
            for (j = 0; j < CLASSHASH_SIZE; j++) {
                cref = ctab->bucket[j];
                for ( ; cref; cref = cref->next) {
                    if (i == 0) {
                        window_t *win = (window_t *)cref->obj;
                        win->store = 0;
                    } else if (i == 1) {
                        stream_t *str = (stream_t *)cref->obj;
                        str->store = 0;
                    }
                    ct++;
                }
            }
        }
    }
    if (!ct) return 0;

    // add entries for windows with styles/pair info + the two general styles
    win = NULL;
    while ((win = gli_window_iterate_backward(win, NULL))) {
        if (win->type == wintype_TextBuffer || win->type == wintype_TextGrid
                || win->type == wintype_Pair || win->type == wintype_Graphics)
            ct++;
    }
    // leave off the last 2 in the event of no styles in use!
    if (gli_window_has_stylehints())
        ct += 2;

    o = glulx_malloc(sizeof(glk_object_save_t) * ct);
    if (!o) return 0;

    ct = 0;
    win = NULL;
    while ((win = gli_window_iterate_backward(win, NULL))) {
        cur = o + ct;
        memset(cur, 0, sizeof(glk_object_save_t));

        cur->type = gidisp_Class_Window;
        cur->id = classes_find_id_for_object(0, win);

        saveWin(win, &cur->obj.win);
        //!!!cur->obj.win = *win;
        win->store = TRUE;
        cur->iscurrent = FALSE; //(win == win_cur);
        classes_normalize_pointers(cur);

        ct++;
        // get stream for window
        if ((win->type == wintype_TextBuffer) || (win->type == wintype_TextGrid)) {

            // write STREAM chunk
            cur = o + ct;
            memset(cur, 0, sizeof(glk_object_save_t));

            cur->type = gidisp_Class_Stream;
            cur->id = classes_find_id_for_object(1, win->str);
            //!!!cur->obj.str = *win->str;

            saveStream(win->str, &cur->obj.str);
            win->str->store = TRUE;
            cur->iscurrent = (win->str == str_cur);
            classes_normalize_pointers(cur);
            ct++;

            // write STYLE chunk
            cur = o + ct;
            memset(cur, 0, sizeof(glk_object_save_t));

            cur->type = type_Style;
            cur->id = classes_find_id_for_object(0, win);

            GLK_STYLE_HINTS hints[style_NUMSTYLES];

            gli_window_get_stylehints(win, hints);
            memcpy(cur->obj.style, hints, sizeof(GLK_STYLE_HINTS) * style_NUMSTYLES);

            ct++;
        } else if (win->type == wintype_Pair) {
            window_pair_t *pairwin = (window_pair_t*)win->data;

            // write PAIR chunk
            cur = o + ct;
            memset(cur, 0, sizeof(glk_object_save_t));

            cur->type = type_Pair;
            cur->id = classes_find_id_for_object(0, win);

            //!!!cur->obj.pair = *((window_pair_t *)win->data);
            saveWinPair(pairwin, &cur->obj.pair);

            // set the children to their ids so we can find the pair on reload
            cur->obj.pair.child1 = classes_find_id_for_object(gidisp_Class_Window, pairwin->child1);
            cur->obj.pair.child2 = classes_find_id_for_object(gidisp_Class_Window, pairwin->child2);
            //!!!classes_normalize_pointers(cur);

            ct++;
        } else if (win->type == wintype_Graphics) {
            // write GRAPHICS chunk
            cur = o + ct;
            memset(cur, 0, sizeof(glk_object_save_t));

            cur->type = type_Graphics;
            cur->id = classes_find_id_for_object(0, win);

            saveWinGfx((window_graphics_t *)win->data, &cur->obj.gfx);
            ct++;
        }
    }
    // now, iterate other classes; window streams should have already been accounted for, but we check this
    for (i = 0; i < num_classes; i++) {
        if ((ctab = classes[i])) {
            for (j = 0; j < CLASSHASH_SIZE; j++) {
                cref = ctab->bucket[j];
                for ( ; cref; cref = cref->next) {
                    if (i == 0) { // windows
                        window_t *win = (window_t *)cref->obj;

                        if (!win->store) {
                            cur = o + ct;
                            memset(cur, 0, sizeof(glk_object_save_t));

                            cur->type = i;
                            cur->id = cref->id;
                        }
                    } else {
                        if (i == 1) { // streams
                            stream_t *str = (stream_t *)cref->obj;

                            if (!str->store) {
                                cur = o + ct;
                                memset(cur, 0, sizeof(glk_object_save_t));
                                cur->type = i;
                                cur->id = cref->id;

                                //!!!cur->obj.str = *str;
                                saveStream(str, &cur->obj.str);
                                cur->iscurrent = (str == str_cur);
                                classes_normalize_pointers(cur);
                                ct++;
                            }
                        } else if (i == 2) {
                            fileref_t *fref = (fileref_t *)cref->obj;

                            cur = o + ct;
                            memset(cur, 0, sizeof(glk_object_save_t));
                            cur->type = i;
                            cur->id = cref->id;

                            //!!!cur->obj.fref = *fref;
                            saveFRef(fref, &cur->obj.fref);
                            classes_normalize_pointers(cur);
                            ct++;
                        } else if (i == 3) { // won't happen here
                            ;
                        }
                    }
                }
            }
        }
    }
    // 2 general styles

    if (gli_window_has_stylehints()) {
        GLK_STYLE_HINTS hints[style_NUMSTYLES];

        cur = o + ct;
        memset(cur, 0, sizeof(glk_object_save_t));
        cur->type = type_Style;
        cur->id = STYLEHINT_TEXT_BUFFER;

        gli_window_get_stylehints((winid_t)STYLEHINT_TEXT_BUFFER, hints);

        memcpy(cur->obj.style, hints, sizeof(GLK_STYLE_HINTS) * style_NUMSTYLES);
        ct++;

        cur = o + ct;
        memset(cur, 0, sizeof(glk_object_save_t));
        cur->type = type_Style;
        cur->id = STYLEHINT_TEXT_GRID;

        gli_window_get_stylehints((winid_t)STYLEHINT_TEXT_GRID, hints);

        memcpy(cur->obj.style, hints, sizeof(GLK_STYLE_HINTS) * style_NUMSTYLES);
        ct++;
    }

    *objs = o;
    return ct;
}
Example #23
0
/* heap_alloc():
   Allocate a block. If necessary, activate the heap and/or extend memory.
   Returns the memory address of the block, or 0 if the operation failed.
*/
glui32 heap_alloc(glui32 len)
{
    heapblock_t *blo, *newblo;

    if (len <= 0)
        fatalError("Heap allocation length must be positive.");

    blo = heap_head;
    while (blo) {
        if (blo->isfree && blo->len >= len)
            break;

        if (!blo->isfree) {
            blo = blo->next;
            continue;
        }

        if (!blo->next || !blo->next->isfree) {
            blo = blo->next;
            continue;
        }

        /* This is a free block, but the next block in the list is also
           free, so we "advance" by merging rather than by going to
           blo->next. */
        newblo = blo->next;
        blo->len += newblo->len;
        if (newblo->next) {
            blo->next = newblo->next;
            newblo->next->prev = blo;
        }
        else {
            blo->next = NULL;
            heap_tail = blo;
        }
        newblo->next = NULL;
        newblo->prev = NULL;
        glulx_free(newblo);
        newblo = NULL;
        continue;
    }

    if (!blo) {
        /* No free area is visible on the list. Try extending memory. How
           much? Double the heap size, or by 256 bytes, or by the memory
           length requested -- whichever is greatest. */
        glui32 res;
        glui32 extension;
        glui32 oldendmem = gEndMem;

        extension = 0;
        if (heap_start)
            extension = gEndMem - heap_start;
        if (extension < len)
            extension = len;
        if (extension < 256)
            extension = 256;
        /* And it must be rounded up to a multiple of 256. */
        extension = (extension + 0xFF) & (~(glui32)0xFF);

        res = resizeMemory(gEndMem+extension, 1);
        if (res)
            return 0;

        /* If we just started the heap, note that. */
        if (heap_start == 0)
            heap_start = oldendmem;

        if (heap_tail && heap_tail->isfree) {
            /* Append the new space to the last block. */
            blo = heap_tail;
            blo->len += extension;
        }
        else {
            /* Append the new space to the block list, as a new block. */
            newblo = glulx_malloc(sizeof(heapblock_t));
            if (!newblo)
                fatalError("Unable to allocate record for heap block.");
            newblo->addr = oldendmem;
            newblo->len = extension;
            newblo->isfree = TRUE;
            newblo->next = NULL;
            newblo->prev = NULL;

            if (!heap_tail) {
                heap_head = newblo;
                heap_tail = newblo;
            }
            else {
                blo = heap_tail;
                heap_tail = newblo;
                blo->next = newblo;
                newblo->prev = blo;
            }

            blo = newblo;
            newblo = NULL;
        }

        /* and continue forwards, using this new block (blo). */
    }

    /* Something strange happened. */
    if (!blo || !blo->isfree || blo->len < len)
        return 0;

    /* We now have a free block of size len or longer. */

    if (blo->len == len) {
        blo->isfree = FALSE;
    }
    else {
        newblo = glulx_malloc(sizeof(heapblock_t));
        if (!newblo)
            fatalError("Unable to allocate record for heap block.");
        newblo->isfree = TRUE;
        newblo->addr = blo->addr + len;
        newblo->len = blo->len - len;
        blo->len = len;
        blo->isfree = FALSE;
        newblo->next = blo->next;
        if (newblo->next)
            newblo->next->prev = newblo;
        newblo->prev = blo;
        blo->next = newblo;
        if (heap_tail == blo)
            heap_tail = newblo;
    }

    alloc_count++;
    /* heap_sanity_check(); */
    return blo->addr;
}