/* 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; }