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. */
/* intern.c,v 2.7 1993/12/19 14:33:25 dmoore Exp */
#include "config.h"

#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#include "db.h"
#include "params.h"
#include "buffer.h"
#include "hashtab.h"
#include "intern.h"
#include "externs.h"


static long total_istrings;
static hash_tab *intern_table = NULL;
static struct interned_string *available_istrings = NULL;


static void generate_istrings(long count)
{
    struct interned_string *hunk;
    int num_4k;
    int i, j;
 
    /* Try allocating them in 4K sets.  The -4 is for some mallocs
       which want to stick some overhead in the space.  This keeps
       things on a single page (hopefully). */
    num_4k = (4096 - 4) / sizeof(struct interned_string);
 
    count = (count / num_4k) + 1;
 
    for (i = 0; i < count; i++) {
        MALLOC(hunk, struct interned_string, num_4k);
        for (j = 0; j < num_4k; j++) {
            hunk->un.next = available_istrings;
            available_istrings = hunk;
            hunk++;
        }
    }
}


static int compare_istrings(const void *entry1, const void *entry2)
{
    const struct interned_string *istring1 = entry1;
    const struct interned_string *istring2 = entry2;

    return muck_stricmp(istring1->un.valid.string, istring2->un.valid.string);
}


static unsigned long make_key_istring(const void *entry)
{
    const struct interned_string *istring = entry;

    return default_hash(istring->un.valid.string);
}


static void delete_istring(void *entry)
{
    struct interned_string *what = entry;

    if (!what) return;

    total_istrings--;

    FREE_STRING(what->un.valid.string);

    what->un.next = available_istrings;
    available_istrings = what;
}


static struct interned_string *new_istring(const char *what)
{
    struct interned_string *result;

    if (!available_istrings) generate_istrings(1);

    result = available_istrings;
    available_istrings = result->un.next;

    total_istrings++;

    result->un.valid.string = ALLOC_STRING(what);
    result->un.valid.refcount = 0;

    return result;
}


struct interned_string *find_interned_string(const char *what)
{
    struct interned_string match;

    match.un.valid.string = what;

    return (struct interned_string *) find_hash_entry(intern_table, &match);
}


struct interned_string *make_interned_string(const char *what)
{
    struct interned_string match;
    struct interned_string *result;

    match.un.valid.string = what;

    result = (struct interned_string *) find_hash_entry(intern_table, &match);

    if (!result) {
        result = new_istring(what);
        add_hash_entry(intern_table, result);
    }

    result->un.valid.refcount++;

    return result;
}


struct interned_string *dup_interned_string(struct interned_string *what)
{
    if (!what) return NULL;

    what->un.valid.refcount++;

    return what;
}


void clear_interned_string(struct interned_string *what)
{
    if (!what) return;

    what->un.valid.refcount--;

    if (what->un.valid.refcount > 0)  return;

    clear_hash_entry(intern_table, what);
}


long total_intern_strings(void)
{
    return total_istrings;
}


void init_intern_strings(const long count)
{
    if (intern_table)  return;

    total_istrings = 0;
    intern_table = init_hash_table("Intern table", compare_istrings,
				   make_key_istring, delete_istring,
				   INTERN_HASH_SIZE);

    generate_istrings(count);
}