/*
 * Copyright (c) 1997-2007, OpenFWTK Development Group
 * All rights reserved. See LICENSE.
 */

/* Variable tables support by ArkanoiD, 2001
   Function names changed to avoid conflicts.
*/
/* Copyright 1997-2000 by Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
   Donated to the public domain.  No warranty. */

#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "firewall2.h"

/* Select how to compute the hash code.  If this macro is defined, it
   should evaluate to an integer by which the previous hash value is
   multipled.  If this macro is not defined, the hash value will be
   rotated. */

#define FACTOR	3	/* Multiplying by 3 should be efficient. */

/* This macro assumes that there are no unused bits in `unsigned'. */

#define BITS(u)		 (CHAR_BIT * sizeof (u))
#define ROTATE_LEFT(u,n) (((u) << (n)) | ((u) >> (BITS (h) - (n))))

#ifdef FACTOR
#define HASH_STEP(h,c) ((h) * FACTOR + (c))
#else
#define HASH_STEP(h,c) (ROTATE_LEFT ((h), 7) ^ (c))
#endif

unsigned hash2 (const char *s, size_t n, unsigned hash_size)
{
  unsigned h = 0;
  if (n != 0)
    {
      /* Speed hack. */
      h = (unsigned char)*s++; --n;
    }
  while (n != 0)
    {
      h = HASH_STEP (h, (unsigned char)*s);
      ++s; --n;
    }
  return h % hash_size;
}

/* Find an entry in a hash table.  Note that letter case matters.  If
   you want to search case-insensitively, convert the search string to
   lowercase and ensure that all table entries are given in
   lowercase. */

const struct hash_entry *
find_he (const struct hash_entry * const *table,
		 unsigned hash_size,
		 const char *s, size_t n)
{
  unsigned h = hash2 (s, n, hash_size);
  const struct hash_entry *p = table[h];
  while (p != NULL)
    {
      if (p->len == n && memcmp (p->name, s, n) == 0)
	return p;
      p = p->next;
    }
  return NULL;
}


const struct hash_entry *find_he2 (const struct hash_descr *descr,
					   const char *s, size_t n)
{
  return find_he (descr->hash, descr->hash_size, s, n);
}

/* Similar functions for variable tables  */

struct hash_entry *
find_vhe (struct hash_entry** table,
		 unsigned hash_size,
		 const char *s, size_t n)
{
  unsigned h = hash2 (s, n, hash_size);
  const struct hash_entry *p = table[h];
  while (p != NULL)
    {
      if (p->len == n && memcmp (p->name, s, n) == 0)
	return (struct hash_entry*) p;
      p = p->next;
    }
  return NULL;
}


struct hash_entry *find_vhe2 (struct hash_descr *descr,
				    const char *s, size_t n)
{
  return find_vhe ((struct hash_entry**)descr->hash, descr->hash_size, s, n);
}
