mux2.0/
mux2.0/game/bin/
mux2.0/game/data/
mux2.0/src/tools/
// htab.cpp - table hashing routines 
//
// $Id: htab.cpp,v 1.1 2000/04/11 07:14:45 sdennis Exp $
//
// MUX 2.0
// Portions are derived from MUX 1.6. Portions are original work.
//
// Copyright (C) 1998 through 2000 Solid Vertical Domains, Ltd. All
// rights not explicitly given are reserved. Permission is given to
// use this code for building and hosting text-based game servers.
// Permission is given to use this code for other non-commercial
// purposes. To use this code for commercial purposes other than
// building/hosting text-based game servers, contact the author at
// Stephen Dennis <sdennis@svdltd.com> for another license.
//

#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"

#include "db.h"
#include "htab.h"
#include "alloc.h"

#include "mudconf.h"
#include "svdhash.h"

/*
 * ---------------------------------------------------------------------------
 * hashreset: Reset hash table stats.
 */
void hashreset(CHashTable *htab)
{
    htab->ResetStats();
}

#pragma pack(1)
static struct
{
    int *hashdata;
    char aTarget[LBUF_SIZE+125];
} htab_rec;
#pragma pack()

/*
 * ---------------------------------------------------------------------------
 * * hashfindLEN: Look up an entry in a hash table and return a pointer to its
 * * hash data.
 */

int *hashfindLEN(void *str, int nStr, CHashTable *htab)
{
    if (str == NULL || nStr <= 0) return NULL;

    unsigned long nHash = CRC32_ProcessBuffer(0, str, nStr);

    HP_DIRINDEX iDir = HF_FIND_FIRST;
    iDir = htab->FindFirstKey(nHash);
    while (iDir != HF_FIND_END)
    {
        HP_HEAPLENGTH nRecord;
        htab->Copy(iDir, &nRecord, &htab_rec);
        int nTarget = nRecord - sizeof(int *);

        if (nTarget == nStr && memcmp(str, htab_rec.aTarget, nStr) == 0)
        {
            return htab_rec.hashdata;
        }
        iDir = htab->FindNextKey(iDir, nHash);
    }
    return NULL;
}

/*
 * ---------------------------------------------------------------------------
 * * hashaddLEN: Add a new entry to a hash table.
 */

int hashaddLEN(void *str, int nStr, int *hashdata, CHashTable *htab)
{
    // Make sure that the entry isn't already in the hash table.  If it
    // is, exit with an error.
    //
    if (str == NULL || nStr <= 0) return -1;

    unsigned long nHash = CRC32_ProcessBuffer(0, str, nStr);

    HP_DIRINDEX iDir = htab->FindFirstKey(nHash);
    while (iDir != HF_FIND_END)
    {
        HP_HEAPLENGTH nRecord;
        htab->Copy(iDir, &nRecord, &htab_rec);
        int nTarget = nRecord - sizeof(int *);

        if (nTarget == nStr && memcmp(str, htab_rec.aTarget, nStr) == 0)
        {
            return -1;
        }
        iDir = htab->FindNextKey(iDir, nHash);
    }

    // Otherwise, add it.
    //
    htab_rec.hashdata = hashdata;
    memcpy(htab_rec.aTarget, str, nStr);
    unsigned int nRecord = nStr + sizeof(int *);
    htab->Insert(nRecord, nHash, &htab_rec);
    return 0;
}

/*
 * ---------------------------------------------------------------------------
 * * hashdelete: Remove an entry from a hash table.
 */

void hashdeleteLEN(void *str, int nStr, CHashTable *htab)
{
    if (str == NULL || nStr <= 0) return;

    unsigned long nHash = CRC32_ProcessBuffer(0, str, nStr);

    HP_DIRINDEX iDir = htab->FindFirstKey(nHash);
    while (iDir != HF_FIND_END)
    {
        HP_HEAPLENGTH nRecord;
        htab->Copy(iDir, &nRecord, &htab_rec);
        int nTarget = nRecord - sizeof(int *);

        if (nTarget == nStr && memcmp(str, htab_rec.aTarget, nStr) == 0)
        {
            htab->Remove(iDir);
        }
        iDir = htab->FindNextKey(iDir, nHash);
    }
}

/*
 * ---------------------------------------------------------------------------
 * * hashflush: free all the entries in a hashtable.
 */

void hashflush(CHashTable *htab)
{
    htab->Reset();
}

/*
 * ---------------------------------------------------------------------------
 * * hashreplLEN: replace the data part of a hash entry.
 */

int hashreplLEN(void *str, int nStr, int *hashdata, CHashTable *htab)
{
    if (str == NULL || nStr <= 0) return 0;

    unsigned long nHash = CRC32_ProcessBuffer(0, str, nStr);

    HP_DIRINDEX iDir = htab->FindFirstKey(nHash);
    while (iDir != HF_FIND_END)
    {
        HP_HEAPLENGTH nRecord;
        htab->Copy(iDir, &nRecord, &htab_rec);
        int nTarget = nRecord - sizeof(int *);

        if (nTarget == nStr && memcmp(str, htab_rec.aTarget, nStr) == 0)
        {
            htab_rec.hashdata = hashdata;
            htab->Update(iDir, nRecord, &htab_rec);
            return 1;
        }
        iDir = htab->FindNextKey(iDir, nHash);
    }
    return 0;
}

void hashreplall(int *old, int *new0, CHashTable *htab)
{
    HP_HEAPLENGTH nRecord;
    for (HP_DIRINDEX iDir = htab->FindFirst(&nRecord, &htab_rec); iDir != HF_FIND_END; iDir = htab->FindNext(&nRecord, &htab_rec))
    {
        if (htab_rec.hashdata == old)
        {
            htab_rec.hashdata = new0;
            htab->Update(iDir, nRecord, &htab_rec);
        }
    }
}


/*
 * ---------------------------------------------------------------------------
 * * hashinfo: return an mbuf with hashing stats
 */

char *hashinfo(const char *tab_name, CHashTable *htab)
{
    char *buff = alloc_mbuf("hashinfo");
    unsigned int hashsize;
    int entries;
    int deletes;
    int scans;
    int hits;
    int checks;
    int max_scan;
    htab->GetStats(&hashsize, &entries, &deletes, &scans, &hits, &checks, &max_scan);
    sprintf(buff, "%-15s %5d %8d %8d %10d %10d %10d %4d", tab_name, hashsize, entries, deletes, scans, hits, checks, max_scan);
    return buff;
}

/*
 * Returns the key for the first hash entry in 'htab'. 
 */

int *hash_firstentry(CHashTable *htab)
{
    HP_HEAPLENGTH nRecord;
    HP_DIRINDEX iDir = htab->FindFirst(&nRecord, &htab_rec);
    if (iDir != HF_FIND_END)
    {
        return htab_rec.hashdata;
    }
    return NULL;
}

int *hash_nextentry(CHashTable *htab)
{
    HP_HEAPLENGTH nRecord;
    HP_DIRINDEX iDir = htab->FindNext(&nRecord, &htab_rec);
    if (iDir != HF_FIND_END)
    {
        return htab_rec.hashdata;
    }
    return NULL;
}

char *hash_firstkey(CHashTable *htab, int *nKeyLength)
{
    HP_HEAPLENGTH nRecord;
    HP_DIRINDEX iDir = htab->FindFirst(&nRecord, &htab_rec);
    if (iDir != HF_FIND_END)
    {
        *nKeyLength = nRecord-sizeof(int *);
        return htab_rec.aTarget;
    }
    *nKeyLength = 0;
    return NULL;
}

char *hash_nextkey(CHashTable *htab, int *nKeyLength)
{
    HP_HEAPLENGTH nRecord;
    HP_DIRINDEX iDir = htab->FindNext(&nRecord, &htab_rec);
    if (iDir != HF_FIND_END)
    {
        *nKeyLength = nRecord-sizeof(int *);
        return htab_rec.aTarget;
    }
    *nKeyLength = 0;
    return NULL;
}

#ifndef STANDALONE

/*
 * ---------------------------------------------------------------------------
 * * search_nametab: Search a name table for a match and return the flag value.
 */

int search_nametab(dbref player, NAMETAB *ntab, char *flagname)
{
    NAMETAB *nt;

    for (nt = ntab; nt->name; nt++) {
        if (minmatch(flagname, nt->name, nt->minlen)) {
            if (check_access(player, nt->perm)) {
                return nt->flag;
            } else
                return -2;
        }
    }
    return -1;
}

/*
 * ---------------------------------------------------------------------------
 * * find_nametab_ent: Search a name table for a match and return a pointer to it.
 */

NAMETAB *find_nametab_ent(dbref player, NAMETAB *ntab, char *flagname)
{
    NAMETAB *nt;

    for (nt = ntab; nt->name; nt++) {
        if (minmatch(flagname, nt->name, nt->minlen)) {
            if (check_access(player, nt->perm)) {
                return nt;
            }
        }
    }
    return NULL;
}

/*
 * ---------------------------------------------------------------------------
 * * display_nametab: Print out the names of the entries in a name table.
 */

void display_nametab(dbref player, NAMETAB *ntab, char *prefix, int list_if_none)
{
    char *buf, *bp, *cp;
    NAMETAB *nt;
    int got_one;

    buf = alloc_lbuf("display_nametab");
    bp = buf;
    got_one = 0;
    for (cp = prefix; *cp; cp++)
        *bp++ = *cp;
    for (nt = ntab; nt->name; nt++) {
        if (God(player) || check_access(player, nt->perm)) {
            *bp++ = ' ';
            for (cp = nt->name; *cp; cp++)
                *bp++ = *cp;
            got_one = 1;
        }
    }
    *bp = '\0';
    if (got_one || list_if_none)
        notify(player, buf);
    free_lbuf(buf);
}



/*
 * ---------------------------------------------------------------------------
 * * interp_nametab: Print values for flags defined in name table.
 */

void interp_nametab(dbref player, NAMETAB *ntab, int flagword, char *prefix, char *true_text, char *false_text)
{
    char *buf, *bp, *cp;
    NAMETAB *nt;

    buf = alloc_lbuf("interp_nametab");
    bp = buf;
    for (cp = prefix; *cp; cp++)
        *bp++ = *cp;
    nt = ntab;
    while (nt->name) {
        if (God(player) || check_access(player, nt->perm)) {
            *bp++ = ' ';
            for (cp = nt->name; *cp; cp++)
                *bp++ = *cp;
            *bp++ = '.';
            *bp++ = '.';
            *bp++ = '.';
            if ((flagword & nt->flag) != 0)
                cp = true_text;
            else
                cp = false_text;
            while (*cp)
                *bp++ = *cp++;
            if ((++nt)->name)
                *bp++ = ';';
        }
    }
    *bp = '\0';
    notify(player, buf);
    free_lbuf(buf);
}

/*
 * ---------------------------------------------------------------------------
 * * listset_nametab: Print values for flags defined in name table.
 */

void listset_nametab(dbref player, NAMETAB *ntab, int flagword, char *prefix, int list_if_none)
{
    char *buf, *bp, *cp;
    NAMETAB *nt;
    int got_one;

    buf = bp = alloc_lbuf("listset_nametab");
    for (cp = prefix; *cp; cp++)
        *bp++ = *cp;
    nt = ntab;
    got_one = 0;
    while (nt->name) {
        if (((flagword & nt->flag) != 0) &&
            (God(player) || check_access(player, nt->perm))) {
            *bp++ = ' ';
            for (cp = nt->name; *cp; cp++)
                *bp++ = *cp;
            got_one = 1;
        }
        nt++;
    }
    *bp = '\0';
    if (got_one || list_if_none)
        notify(player, buf);
    free_lbuf(buf);
}

/*
 * ---------------------------------------------------------------------------
 * * cf_ntab_access: Change the access on a nametab entry.
 */

extern void FDECL(cf_log_notfound, (dbref, char *, const char *, char *));

CF_HAND(cf_ntab_access)
{
    NAMETAB *np;
    char *ap;

    for (ap = str; *ap && !Tiny_IsSpace[(unsigned char)*ap]; ap++) ;
    if (*ap)
        *ap++ = '\0';

    while (Tiny_IsSpace[(unsigned char)*ap])
        ap++;

    for (np = (NAMETAB *) vp; np->name; np++)
    {
        if (minmatch(str, np->name, np->minlen))
        {
            return cf_modify_bits(&(np->perm), ap, extra, player, cmd);
        }
    }
    cf_log_notfound(player, cmd, "Entry", str);
    return -1;
}

#endif STANDALONE