area_current/castle/
area_current/gahld/
clans/
player/
player/c/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "merc.h"

#define USE_HASH 

#define STR_HASH_SIZE	1000
#define SINGLE_STRING   65534
#define LEN_ADJ         1       /* MAX_STR_LENGTH factor - 1<64k 2<128k etc */

void		show_hash( int count );

struct hashstr_data *string_hash[STR_HASH_SIZE];
int str_leng_alloc=0;

int get_hash( char *str)
  {
  register int c1;
  register char *pt;

  for( c1=0, pt=str, str_leng_alloc=0; *pt!='\0'; str_leng_alloc++, pt++, c1++)
    c1+=*pt;

  return( c1%STR_HASH_SIZE );
  }

/*
 * Check hash table for existing occurance of string.
 * If found, increase link count, and return pointer,
 * otherwise add new string to hash table, and return pointer.
 */

  /*  Type 0=Normal 1=Single (this is not hashed ) */
char *str_alloc( char *str,int str_type )
{

#ifdef USE_HASH

   register int len, hash, psize, lnp;
   char *pt, emp[2];
   register struct hashstr_data *ptr;


   *emp='\0';
   if(str==NULL)
     str = emp;

   hash = get_hash(str);
   len = str_leng_alloc;

   lnp=len/LEN_ADJ;
   psize = sizeof(struct hashstr_data);
   if( str_type == 0 )
   for (ptr = string_hash[hash]; ptr; ptr = ptr->next )
     if ( lnp == ptr->length && !strcmp(str,(char *)ptr+psize) )
       {
       if( ptr->links < SINGLE_STRING-1 )
         {
	 ++ptr->links;
	 return (char *) ptr+psize;
         }
       }
   pt = alloc_mem(len+psize+1);
   ptr=(struct hashstr_data *)pt;

   /* Let's quickly change the header of the raw memory  -  S for String */
   set_block_type( 'S', pt );

   if( str_type == 0 )
     ptr->links		= 1;
   else
   if( str_type == 1 )
     ptr->links		= SINGLE_STRING;

   ptr->length		= lnp;
   if (len)
     strcpy( (char *) ptr+psize, str );
   else
     strcpy( (char *) ptr+psize, "" );
   ptr->next		= string_hash[hash];
   if( string_hash[hash]!=NULL )
     string_hash[hash]->prev = ptr;
   ptr->prev            = NULL;
   string_hash[hash]	= ptr;
   return (char *) ptr+psize;

#else

    static char *ret;
    int len;

   if(str==NULL )
     return(NULL);
   if( *str=='\0')
     return(str_empty);

    len = strlen(str)+1;

    CREATE( ret, char, len );
    strcpy( ret, str );
   if( str_type != 1 )
     set_block_type( 'S', pt );
   else
     set_block_type( 'P', pt );
    return ret;  
#endif
}

char *str_alloc_single( char *str)
{
  return( str_alloc( str , 1));
}

/*
 * Used to make a quick copy of a string pointer that is known to be already
 * in the hash table.  Function increments the link count and returns the
 * same pointer passed.
 */
char *quick_link( char *str )
{
#ifdef USE_HASH
    register struct hashstr_data *ptr;

   if(str==NULL)
     return( NULL );

    /* Let's hope that the CRC works here 
    if( get_string_size(str)>=0 )
      return( str_alloc( str ) ); */

    ptr = (struct hashstr_data *) (str - sizeof(struct hashstr_data));
    if ( ptr->links == 0 )
    {
	fprintf(stderr, "quick_link: bad pointer\n" );
	return NULL;
    }
    if ( ptr->links < SINGLE_STRING-1 )
	++ptr->links;
    else
        return( str_alloc( str,0) );
    return str;
#else
   if(str==NULL)
     return( NULL );
   if(*str=='\0')
     return(str_empty);
   if( *(str-2)=='P' || *(str-2)=='p' )
     return( str );
   return( str_alloc(str,0) );
#endif
}

/*
 * Used to remove a link to a string in the hash table.
 * If all existing links are removed, the string is removed from the
 * hash table and disposed of.
 * returns how many links are left, or -1 if an error occurred.
 */
int str_free( char *str )
{
#ifdef USE_HASH
    register int hash, psize;
    struct hashstr_data *ptr;
    char *pt;
    register struct hashstr_data *ptrp;

    if( str==NULL )
      return(0);

    /* Let's hope that the CRC works here 
    if( get_string_size(str)>=0 || get_alloc_size_perm(str)>=0 )
      {
      free_mem( &str, 0);
      return( 0 );
      }  */

    hash = get_hash(str);
    psize = sizeof( struct hashstr_data);
    ptr = (struct hashstr_data *) (str - psize);
    if ( ptr->links == 0 )
    {
	fprintf(stderr, "str_free: bad pointer\n" );
	return -1;
    }
    if ( ptr->links==SINGLE_STRING || --ptr->links == 0 )
    {

    ptrp = ptr->prev;
    if( ptrp!=NULL )
      {
      ptrp->next = ptr->next;
      }
    else
      {
      string_hash[hash]=ptr->next;
      }

    /* Ok let's use ptrp for the next item */
    ptrp = ptr->next;
    if( ptrp!=NULL )
      ptrp->prev = ptr->prev;


    pt = (char *)ptr;
    free_mem( &pt, 0 );
    return( 0 );

     /*
	if ( string_hash[hash] == ptr )
	{
	    string_hash[hash] = ptr->next;
            pt = (char *)ptr;
	    free_mem(&pt,0);
	    return 0;
	}
	for ( ptr2 = string_hash[hash]; ptr2; ptr2 = ptr2_next )
	{
	    ptr2_next = ptr2->next;
	    if ( ptr2_next == ptr )
	    {
		ptr2->next = ptr->next;
                pt = (char *)ptr;
		free_mem(&pt, 0);
		return 0;
	    }
	}
	fprintf( stderr, "str_free: pointer not found for string: %s\n", str );
	return -1;
     */
    }
    return ptr->links;

#else

  if( str==NULL || str==str_empty )
    return( 0 );

  free_mem( &str, 0);
  return( 0 );

#endif
}

void show_hash( int count )
{
    struct hashstr_data *ptr;
    int x, c;

    for ( x = 0; x < count; x++ )
    {
	for ( c = 0, ptr = string_hash[x]; ptr; ptr = ptr->next, c++ );
	fprintf( stderr, " %d", c );
    }
    fprintf( stderr, "\n" );
}

void hash_dump( int hash )
{
    struct hashstr_data *ptr;
    char *str;
    int c, psize;

    if ( hash > STR_HASH_SIZE || hash < 0 )
    {
	fprintf( stderr, "hash_dump: invalid hash size\n\r" );
	return;
    }
    psize = sizeof(struct hashstr_data);
    for ( c=0, ptr = string_hash[hash]; ptr; ptr = ptr->next, c++ )
    {
	str = (char *) (((int) ptr) + psize);
	fprintf( stderr, "Lnp:%4d Lnks:%5d Str: %s\n\r",
	  ptr->length, ptr->links, str );
    }
    fprintf( stderr, "Total strings in hash %d: %d\n\r", hash, c );
}

char *check_hash( char *str )
{
   static char buf[1024];
   int len, hash, psize, p = 0, c, lnp;
   struct hashstr_data *ptr, *fnd;

   buf[0] = '\0';
   len = strlen(str);
   lnp = len/LEN_ADJ;
   psize = sizeof(struct hashstr_data);
   hash = get_hash(str);
   for (fnd = NULL, ptr = string_hash[hash], c = 0; ptr; ptr = ptr->next, c++ )
     if ( lnp == ptr->length && !strcmp(str,(char *)ptr+psize) )
     {
	fnd = ptr;
	p = c+1;
     }
   if ( fnd )
     sprintf( buf, "Hash info on string: %s\n\rLinks: %d  Position: %d/%d  Hash: %d  Lnp: %d\n\r",
	  str, fnd->links, p, c, hash, fnd->length );
   else
     sprintf( buf, "%s not found.\n\r", str );
   return buf;
}

char *hash_stats( char *argument )
{
    static char buf[MAX_STRING_LENGTH];
    char buft[MAX_STRING_LENGTH];
    struct hashstr_data *ptr;
    int x, c, total, totlinks, unique, bytesused, wouldhave, hilink;
    int nonhashed, avgtotal, devtotal, hihash, hihashx;
    int hashamounts[STR_HASH_SIZE];

    totlinks = unique = total = bytesused = wouldhave = hilink = 0;
    nonhashed=0;
    devtotal=0;
    hihashx=0;
    hihash=0;
    *buf='\0';
    for ( x = 0; x < STR_HASH_SIZE; x++ )
    {
        hashamounts[x]=0;
	for ( c = 0, ptr = string_hash[x]; ptr; ptr = ptr->next, c++ )
	{
	   total++;
           hashamounts[x]++;
	   if ( ptr->links == 1 )
	     unique++;
	   if ( ptr->links > hilink  && ptr->links< SINGLE_STRING )
	     hilink = ptr->links;
	   if ( ptr->links<SINGLE_STRING )
	     totlinks += ptr->links;
           else
             nonhashed++;
	   bytesused += (ptr->length*LEN_ADJ + 1 + sizeof(struct hashstr_data));
	   if ( ptr->links<SINGLE_STRING )
	     wouldhave += (ptr->links * (ptr->length*LEN_ADJ + 1));
        }
        if( !strcasecmp( argument, "links" ) )
          {
          sprintf( buft, "  %5d:%-6d      ", x, hashamounts[x] );
          strcat( buf, buft );
          }
    }
    avgtotal = total/STR_HASH_SIZE;
    for ( x = 0; x < STR_HASH_SIZE; x++ )
      {
      devtotal += abs( hashamounts[x]-avgtotal );
      if( hashamounts[x] > hihash )
        {
        hihash = hashamounts[x];
        hihashx = x;
        }
      }
    devtotal /= STR_HASH_SIZE;

    sprintf( buft, "Hash strings allocated:%8d  Total links  : %d\n\rString bytes allocated:%8d  Bytes saved  : %d\n\rUnique (wasted) links :%8d  Hi-Link count: %d\n\rNonhashed Strings     : %d\n\rAverage Hashs         : %-8d  StdDev Hashs: %-8d\n\rMaximum Hashs         : %-8d  (Hash=%d)\n\r",
	total, totlinks, bytesused, wouldhave - bytesused, unique, hilink,
        nonhashed, avgtotal, devtotal, hihash, hihashx );
    strcat( buf, buft );
    return buf;
}

void show_high_hash( int top )
{
    struct hashstr_data *ptr;
    int x, psize;
    char *str;

    psize = sizeof(struct hashstr_data);
    for ( x = 0; x < STR_HASH_SIZE; x++ )
	for ( ptr = string_hash[x]; ptr; ptr = ptr->next )
	  if ( ptr->links >= top )
	  {
	     str = (char *) (((int) ptr) + psize);
 	     fprintf( stderr, "Links: %5d  String: >%s<\n\r", ptr->links, str );
	  }
}