/
driver3.2@242/autoconf/
driver3.2@242/doc/LPC/
driver3.2@242/hosts/
driver3.2@242/hosts/amiga/NetIncl/
driver3.2@242/hosts/amiga/NetIncl/netinet/
driver3.2@242/hosts/amiga/NetIncl/sys/
driver3.2@242/hosts/atari/
driver3.2@242/hosts/fcrypt/
driver3.2@242/mudlib/
driver3.2@242/mudlib/sys/
driver3.2@242/util/
driver3.2@242/util/indent/hosts/next/
driver3.2@242/util/make_docs/
#include <stdio.h>

#include "lint.h"
#include "interpret.h"
#include "object.h"
#include "exec.h"
#define USES_SVALUE_STRLEN
#include "smalloc.h"
#include "lang.h"
#include "instrs.h"

#if defined(AMIGA)
#include "hosts/amiga/ixfile.h"
#endif

/*
 * Write statistics about objects on file.
 */
#ifdef MAPPINGS
static int svalue_size PROT((struct svalue *));

struct svalue_size_locals {
    mp_int total;
    int num_values;
};

void svalue_size_map_filter(key, values, extra)
    struct svalue *key;
    struct svalue *values;
    char *extra;
{
    struct svalue_size_locals *locals;
    int i;

    locals = (struct svalue_size_locals*)extra;
    locals->total += svalue_size(key);
    for(i = locals->num_values; --i >= 0; ) {
	locals->total += svalue_size(values++) + sizeof(struct svalue);
    }
}
#endif

extern struct object *obj_list;

static int svalue_size(v)
    struct svalue *v;
{
    mp_int i, total;

    switch(v->type) {
    case T_OBJECT:
    case T_NUMBER:
#ifdef FLOATS
    case T_FLOAT:
#endif
	return 0;
    case T_STRING:
	/* Include some malloc overhead. */
	if (v->x.string_type == STRING_SHARED)
	    return strlen(v->u.string) + sizeof(short) + 3*sizeof(char*) &
	      ~(sizeof(char *) - 1);
	return svalue_strlen(v) + 2*sizeof(char *) & ~(sizeof(char *) - 1);
    case T_SYMBOL:
	return strlen(v->u.string) + sizeof(short) + 3*sizeof(char*) &
	  ~(sizeof(char *) - 1);
#ifdef MAPPINGS
    case T_MAPPING:
    {
	extern int register_pointer PROT((char *));
	extern void walk_mapping PROT((
		struct mapping *,
		void (*)(struct svalue *, struct svalue *, char *),
		char *
	));

	struct svalue_size_locals locals;
	struct condensed_mapping *cm;

	if (register_pointer( (char *)(v->u.map) ) ) return 0;

	cm = v->u.map->condensed;
	locals.total = cm->string_size + cm->misc_size;
	locals.num_values = v->u.map->num_values;
	walk_mapping(v->u.map, svalue_size_map_filter, (char *)&locals);
	if (v->u.map->hash)
	    locals.total +=
	      sizeof(struct hash_mapping) +
		v->u.map->hash->mask * sizeof(struct map_chain *) +
		  v->u.map->hash->used *
		    (sizeof (struct map_chain) - sizeof(struct svalue));
	return locals.total;
    }
#endif
    case T_POINTER:
    case T_QUOTED_ARRAY:
    {
	extern struct vector null_vector;

	extern int register_pointer PROT((char *));

	if (v->u.vec == &null_vector) return 0;
	if (register_pointer( (char *)(v->u.vec) ) ) return 0;
#ifdef MALLOC_smalloc
	total = malloced_size(v->u.vec) * sizeof(p_int);
#else
	total = sizeof *v->u.vec - sizeof v->u.vec->item +
	  sizeof(struct svalue) * v->u.vec->size + sizeof(char *);
#endif
	for (i=0; i < v->u.vec->size; i++) {
	    total += svalue_size(&v->u.vec->item[i]);
	}
	return total;
    }
    case T_CLOSURE:
    {
	extern int register_pointer PROT((char *));
	int num_values;
	struct svalue *svp;
	struct lambda *l;

	if (!CLOSURE_MALLOCED(v->x.closure_type)) return 0;
	if (!CLOSURE_REFERENCES_CODE(v->x.closure_type)) {
	    /* CLOSURE_LFUN || CLOSURE_IDENTIFIER || CLOSURE_PRELIMINARY */
	    return sizeof *v->u.lambda + sizeof(char *);
	}
	/* CLOSURE_LAMBDA */
	total = 0;
	l = v->u.lambda;
	if (v->x.closure_type == CLOSURE_BOUND_LAMBDA)
	{
	    total += sizeof *l - sizeof l->function + sizeof l->function.lambda;
	    l = l->function.lambda;
	}
	num_values = EXTRACT_UCHAR(&l->function.code[0]);
	if (num_values == 0xff)
	    num_values = ((struct svalue *)l)[-0xff].u.number;
	svp = (struct svalue *)l - num_values;
	if (register_pointer( (char *)svp ) ) return 0;
#ifdef MALLOC_smalloc
	total += malloced_size(svp) * sizeof(p_int);
#else
	total += sizeof(struct svalue) * num_values + sizeof (char *);
	{
	    char *p = &l->function.code[2];
	    do {
		switch(*++p) {
		  case F_RETURN -F_OFFSET:
		  case F_RETURN0-F_OFFSET:
		    break;
		}
	    } while (1);
	    total += p - (char *)l + (sizeof(char *) - 1) &
		~(sizeof(char *) - 1);
	}
#endif
	while (--num_values >= 0) {
	    total += svalue_size(svp++);
	}
	return total;
    }
    default:
	fatal("Illegal type: %d\n", v->type);
    }
    /*NOTREACHED*/
#ifdef lint
    return 0;
#endif
}

static mp_int data_size(ob)
    struct object *ob;
{
    struct pointer_record;
    extern void init_pointer_table PROT((struct pointer_record **));
    extern void free_pointer_table PROT((void));

    mp_int total = 0, i;
    struct pointer_record *pointer_table_space[256];

    init_pointer_table(pointer_table_space);
    if (ob->prog) {
        init_pointer_table(pointer_table_space);
        for (i = 0; i < ob->prog->num_variables; i++)
    	    total += svalue_size(&ob->variables[i]) + sizeof (struct svalue);
    }
    free_pointer_table();
    return total;
}

void dumpstat() {
    FILE *f;
    struct object *ob;

    f = fopen("OBJ_DUMP", "w");
    if (f == 0)
	return;
    add_message("Dumping to OBJ_DUMP ...");
    for (ob = obj_list; ob; ob = ob->next_all) {
	mp_int tmp;
	if (ob->prog && (ob->prog->ref == 1 || !(ob->flags & O_CLONE)))
	    tmp = ob->prog->total_size;
	else
	    tmp = 0;
	fprintf(f, "%-20s %5ld ref %2d %s %s (%ld) %s\n", ob->name,
		tmp + data_size(ob) + sizeof (struct object), ob->ref,
		ob->flags & O_HEART_BEAT ? "HB" : "  ",
		ob->super ? ob->super->name : "--",/*ob->cpu*/ 0L,
		ob->swap_num >=0 ? "SWAPPED" : "");
    }
    add_message("done.\n");
    fclose(f);
}