/* $Id: scache.c,v 1.3 2005/07/05 03:17:54 sheik Exp $ */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "h.h"
#include "memcount.h"

static int  hash(char *);	/* keep it hidden here */
/*
 * ircd used to store full servernames in anUser as well as in the
 * whowas info.  there can be some 40k such structures alive at any
 * given time, while the number of unique server names a server sees in
 * its lifetime is at most a few hundred.  by tokenizing server names
 * internally, the server can easily save 2 or 3 megs of RAM.
 * -orabidoo
 */
/*
 * I could have tucked this code into hash.c I suppose but lets keep it
 * separate for now -Dianora
 */

#define SCACHE_HASH_SIZE 257

typedef struct scache_entry
{
    char        name[HOSTLEN + 1];
    struct scache_entry *next;
} SCACHE;

static SCACHE *scache_hash[SCACHE_HASH_SIZE];

/* renamed to keep it consistent with the other hash functions -Dianora */
/* orabidoo had named it init_scache_hash(); */

void clear_scache_hash_table(void)
{
    memset((char *) scache_hash, '\0', sizeof(scache_hash));
}

static int hash(char *string)
{
    int         hash_value;
   
    hash_value = 0;
    while (*string)
	hash_value += (*string++ & 0xDF);

    return hash_value % SCACHE_HASH_SIZE;
}

/*
 * this takes a server name, and returns a pointer to the same string
 * (up to case) in the server name token list, adding it to the list if
 * it's not there.  care must be taken not to call this with
 * user-supplied arguments that haven't been verified to be a valid,
 * existing, servername.  use the hash in list.c for those.  -orabidoo
 */
char *find_or_add(char *name)
{
    int         hash_index;
    SCACHE     *ptr, *newptr;

    ptr = scache_hash[hash_index = hash(name)];
    while (ptr) 
    {
	if (!mycmp(ptr->name, name))
	    return (ptr->name);
	else
	    ptr = ptr->next;
    }

    /* not found -- add it */
    if ((ptr = scache_hash[hash_index])) 
    {
	newptr = scache_hash[hash_index] = (SCACHE *) MyMalloc(sizeof(SCACHE));
	strncpyzt(newptr->name, name, HOSTLEN);
	newptr->next = ptr;
	return (newptr->name);
    }
    else
    {
	ptr = scache_hash[hash_index] = (SCACHE *) MyMalloc(sizeof(SCACHE));
	strncpyzt(ptr->name, name, HOSTLEN);
	ptr->next = (SCACHE *) NULL;
	return (ptr->name);
    }
}

/* list all server names in scache very verbose */

void list_scache(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    int         hash_index;
    SCACHE     *ptr;

    for (hash_index = 0; hash_index < SCACHE_HASH_SIZE; hash_index++) 
    {
	ptr = scache_hash[hash_index];
	while (ptr) 
	{
	    if (ptr->name)
		sendto_one(sptr, ":%s NOTICE %s :%s",
			   me.name, parv[0], ptr->name);
	    ptr = ptr->next;
	}
    }
}

u_long
memcount_scache(MCscache *mc)
{
    SCACHE *ce;
    int i;

    mc->file = __FILE__;

    for (i = 0; i < sizeof(scache_hash)/sizeof(scache_hash[0]); i++)
    {
        for (ce = scache_hash[i]; ce; ce = ce->next)
        {
            mc->cached.c++;
            mc->cached.m += sizeof(*ce);
        }
    }

    mc->s_hash.c = sizeof(scache_hash)/sizeof(scache_hash[0]);
    mc->s_hash.m = sizeof(scache_hash);

    mc->total.c += mc->cached.c;
    mc->total.m += mc->cached.m;

    return mc->total.m;
}


syntax highlighted by Code2HTML, v. 0.9.1