tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore.  All rights reserved. */
/* code.c,v 2.7 1997/08/30 06:44:01 dmoore Exp */
#include "config.h"

#include "db.h"
#include "code.h"
#include "params.h"
#include "externs.h"


struct code_entry {
    dbref program;
    struct code *code;
};


/* Hash table of programs currently being edited. */
static hash_tab *code_table = NULL;


/* Hash table routines.  Maps a program # -> codes. */
static unsigned long hash_code_entry(const void *entry)
{
    const struct code_entry *info = entry;

    return dbref2long(info->program);
}


static int compare_code_entries(const void *entry1, const void *entry2)
{
    const struct code_entry *info1 = entry1;
    const struct code_entry *info2 = entry2;

    return (info1->program != info2->program);
}


static void delete_code_entry(void *entry)
{
    struct code_entry *info = entry;

    /* #### i think this should call clear_code? */
    clear_code(info->code);
    FREE(info);
}


void init_code_table(void)
{
    if (code_table) return;

    code_table = init_hash_table("Prog -> Code Segment",
				 compare_code_entries,
				 hash_code_entry, delete_code_entry,
				 CODE_HASH_SIZE);
}


void clear_code_table(void)
{
    clear_hash_table(code_table);
    code_table = NULL;
}


struct code *get_code(const dbref program)
{
    struct code_entry match;
    const struct code_entry *result;

    match.program = program;
    result = find_hash_entry(code_table, &match);
    
    if (!result) return NULL;

    return result->code;
}


void add_code(const dbref program, struct code *code)
{
    struct code_entry match;
    struct code_entry *info;

    match.program = program;
    info = (struct code_entry *) find_hash_entry(code_table, &match);
    
    if (!info) {
	MALLOC(info, struct code_entry, 1);
	info->program = program;
	info->code = NULL;
	add_hash_entry(code_table, info);
    }
    /* First up the ref count on the new code, and down the previous. */
    code = dup_code(code);
    if (info->code) clear_code(info->code);

    code->next = info->code;
    code->prev = &info->code; 
    if (info->code)
	info->code->prev = &code->next;
    info->code = code;
}


/* This is for recycling a program. */
void delete_code(const dbref program)
{
    struct code_entry match;
    struct code *first;
    struct code *temp;

    first = get_code(program);
    if (!first) return;

    clear_code(first);

    first = get_code(program);

    if (first) {
	/* Something still here.  Detach the code chain, and mark
	   each item so that the interpreter kicks people out of them. */
	first->prev = NULL;
 
        for (temp = first; temp; temp = temp->next)
            temp->object = NOTHING;
    }

    match.program = program;
    clear_hash_entry(code_table, &match);
}


/*  make_code:  creates an empty code block
 */
struct code *make_code(dbref obj, int num_funcs)
{
    struct code *result;

    MALLOC(result, struct code, 1);
    result->refcount = 1;
    result->object = obj;
    result->num_funcs = num_funcs;
    if (num_funcs)
        MALLOC(result->funcs, struct func_addr *, num_funcs);
    else
        result->funcs = NULL;
    result->next = NULL;
    result->prev = NULL;
    return result;
}


/*  dup_code: this ups the refcount on a code block.
 */
struct code *dup_code(struct code *code)
{
    if (code) code->refcount++;
    return code;
}


/*  clear_code:  tells the world you're done with whatever you were doing
 *  with this struct code.  may or may not cause it to be flushed from
 *  memory. this is called from outside the compiler, during recycles, etc.
 */
void clear_code(struct code *code)
{
    int x, y;

    if (!code) return;

    code->refcount--;
    if (code->refcount > 0) return;
    if (code->refcount < 0) {
	log_status("CODE: refcount on code struct below 0");
	return;
    }
	

    for (y = code->num_funcs; y; --y) {
	struct func_addr *victim = code->funcs[y-1];

	for (x = 0; x < victim->num_inst; x++)
	    clear_inst_code(&(victim->bytecode[x]));
    }

    for (y = code->num_funcs; y; --y) {
        struct func_addr *victim = code->funcs[y-1];

	FREE(victim->bytecode);

        if (victim->name)
            FREE_STRING(victim->name);
        FREE(victim);
    }

    if (code->funcs)
        FREE(code->funcs);

    /* unlink this code from it's list. */
    if (code->prev)
	*(code->prev) = code->next;
    if (code->next)
	code->next->prev = code->prev;

    FREE(code);
}


/*  get_code_size: finds out the # of functions and instructions for
 *  a code block.
 */
void get_code_size(struct code *code, int *num_func, int *num_inst)
{
    int funcs = 0;
    int insts = 0;
    int i;

    if (code) {
	funcs = code->num_funcs;
	for (i = 0; i < funcs; i++) {
	    insts += code->funcs[i]->num_inst;
	}
    }
    *num_func = funcs;
    *num_inst = insts;
}