/* Copyright (c) 1993 Stephen F. White */
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <sys/time.h>
#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_proto.h"
#include "netio.h"
#include "servers.h"
static int dbtop(void);
static void set_dbtop(int newdbtop);
extern GENPTR malloc(int);
void free(GENPTR);
static void free_vars(Object *o, Vardef *v);
static void store_malloc(GENPTR where, int size);
static void delete_malloc(GENPTR where);
Object *
new_object(void)
{
Object *o = MALLOC(Object, 1);
o->id.server = 0; o->id.id = -1;
o->ref = 1;
o->parents = 0;
o->locks = 0;
o->vars = 0;
o->verbs = 0;
o->symbols = 0;
o->methods = 0;
o->st_size = 0;
o->methods = 0;
o->last_search = -1;
return o;
}
Object *
clone(Objid pid)
{
Object *o;
int top;
if (pid.server != 0 || pid.id < 0) {
return 0;
} else {
top = dbtop() + 1;
set_dbtop(top);
o = new_object();
o->id.server = 0;
o->id.id = top;
sym_init(o);
o->parents = list_new(1);
o->parents->el[0].type = OBJ;
o->parents->el[0].v.obj = pid;
assign_object(o->id, o);
return o;
}
}
int
destroy(Objid oid)
{
if (!valid(oid)) {
return 1;
} else {
cache_del(oid.id, 0);
return 0;
}
}
static int
dbtop(void)
{
Var top;
if (sys_get_global("dbtop", &top) != E_NONE) {
return 0;
} else if (top.type != NUM) {
writelog();
fprintf(stderr, "#%d.dbtop non-numeric\n", SYS_OBJ);
return 0;
} else {
return top.v.num;
}
}
static void
set_dbtop(int newdbtop)
{
Var v;
v.type = NUM; v.v.num = newdbtop;
sys_assign_global("dbtop", v);
}
void
assign_object(Objid oid, Object *new)
{
Object *old;
if (oid.server != 0 || oid.id < 0) {
return;
}
if ((old = retrieve(oid))) {
old->ref++; /* save old obj till we're done */
cache_put(new, oid.id); /* put in new one */
var_copy_vars(old, new); /* copy vars from old to new */
free_object(old); /* really free old one */
} else {
cache_put(new, oid.id);
}
if (oid.id > dbtop()) {
set_dbtop(oid.id);
}
}
static void
free_vars(Object *o, Vardef *v)
{
Vardef *vnext;
if (!v) {
return;
}
for (; v; v = vnext) {
vnext = v->next;
sym_free(o, v->name);
var_free(v->value);
FREE(v);
}
}
void
free_method(Object *o, Method *m)
{
if (--m->ref) {
return;
}
sym_free(o, m->name);
free_vars(o, m->vars);
opcode_free_symbols(o, m);
if (m->code) {
FREE(m->code);
}
FREE(m);
}
void
free_object(Object *o)
{
Method *m, *mnext;
Verbdef *vb, *vbnext;
int i, hval;
if (--o->ref) { /* if refcount is nonzero, */
return; /* don't free object */
}
if (o->parents) {
list_free(o->parents);
}
if (o->methods) {
for (hval = 0; hval < o->methods->size; hval++) {
for (m = o->methods->table[hval]; m; m = m->next) {
mnext = m->next;
free_method(o, m);
}
}
FREE(o->methods);
}
for (vb = o->verbs; vb; vb = vbnext) {
vbnext = vb->next;
sym_free(o, vb->verb);
if (vb->prep >= 0) {
sym_free(o, vb->prep);
}
sym_free(o, vb->method);
FREE(vb);
}
if (o->vars) {
for (hval = 0; hval < o->vars->size; hval++) {
free_vars(o, o->vars->table[hval]);
}
FREE(o->vars);
}
if (o->symbols) {
for (i = 0; i < o->nsymb; i++) {
if (o->symbols[i].ref > 0) {
string_free(o->symbols[i].s);
}
}
FREE(o->symbols);
}
FREE(o);
}
struct mem_tbl {
GENPTR where;
int size;
struct mem_tbl *next;
};
struct mem_tbl *sm_head;
static void
store_malloc(GENPTR where, int size)
{
struct mem_tbl *s;
s = (struct mem_tbl *) malloc(sizeof (struct mem_tbl));
s->where = where;
s->size = size;
s->next = sm_head;
sm_head = s;
}
static void
delete_malloc(GENPTR where)
{
struct mem_tbl *s, *t;
if (where == sm_head->where) {
s = sm_head;
sm_head = sm_head->next;
free((GENPTR) s);
return;
}
for (s = sm_head; s->next; s = s->next) {
if (s->next->where == where) {
t = s->next;
s->next = s->next->next;
free((GENPTR) t);
return;
}
}
writelog();
fprintf(stderr, "MALLOC: non-malloc'ed memory freed at 0x%x!\n",
(int) where);
kill(getpid(), SIGQUIT);
}
static int chunks = 0;
const char
*check_malloc(void)
{
struct mem_tbl *s;
static char buf[80];
int total = 0;
#ifdef DEBUG_MALLOC
for (s = sm_head; s; s = s->next) {
total += s->size;
}
sprintf(buf, "%d bytes used in %d chunks.", total, chunks);
#else
sprintf(buf, "%d chunks of memory allocated.", chunks);
#endif
return buf;
}
GENPTR
cool_malloc(unsigned size)
{
GENPTR memptr;
memptr = malloc(size);
if (!memptr) {
writelog();
fprintf(stderr, "MALLOC (size %d bytes) failed!\n", size);
kill(getpid(), SIGQUIT);
}
#ifdef DEBUG_MALLOC
store_malloc(memptr, size);
#endif
chunks++;
return memptr;
}
void
cool_free(GENPTR ptr)
{
free(ptr);
#ifdef DEBUG_MALLOC
delete_malloc(ptr);
#endif
chunks--;
}
void write_object(FILE *f, Objid oid);
static char *written;
void
write_flatfile(const char *dbfile, const char *dumpfile)
{
FILE *f;
Objid oid;
int top;
init(dbfile, 0, 1);
top = dbtop();
if (!strcmp(dumpfile, "-")) {
f = stdout;
} else {
f = fopen(dumpfile, "w");
if (!f) {
writelog();
perror(dumpfile);
return;
} /* if */
} /* if */
written = MALLOC(char, top + 1);
if (!written) return;
oid.server = 0;
for (oid.id = 0; oid.id <= top; oid.id++) written[oid.id] = 0;
for (oid.id = 0; oid.id <= top; oid.id++) {
write_object(f, oid);
cache_reset();
} /* for */
FREE(written);
fclose(f);
shutdown_server();
} /* write_flatfile */
void
write_object(FILE *f, Objid oid)
{
String *listing;
int i;
Object *o = retrieve(oid);
if (!o || written[oid.id]) return;
for (i = 0; i < o->parents->len; i++) {
if (o->parents->el[i].v.obj.id > oid.id) {
write_object(f, o->parents->el[i].v.obj);
} /* if */
} /* for */
listing = decompile_object(o);
listing = string_strip_cr(listing);
fputs(listing->str, f);
string_free(listing);
written[oid.id] = 1;
}