/*
 *  smoke16/src/hashtbl.c - Symbol-table management for the SMOKE-16 assembler.
 *  $Revision: 1.16 $
 *  Copyright 1997, Benjamin Sittler
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <stdio.h>
#include <string.h>
#include <smoke16/hashpjw.h>
#include <smoke16/hashtbl.h>

/* wordhash returns hash value of word in a word node */
int wordhash( struct Node *wordnode )
{
   return hashpjw( wordnode->word );
}

/* wordcompare returns comparison of two word nodes */
int wordcompare( struct Node *word1, struct Node *word2 )
{
   int length1, length2;

   length1 = strlen( word1->word );
   length2 = strlen( word2->word );
   if ( length1 != length2 )
      return 1;
   return strncmp(word1->word,
		  word2->word,
		  length1);
}

/* lookup( hashtable, node, hash(node), compare( node1, node2 ) ) */
struct Node *lookup( struct Node *table[],
		     struct Node *needle,
		     int (*hash)(struct Node *),
		     int (*compare)(struct Node *, struct Node *) )
{
   struct Node *node;

   node = ( table[ (*hash)(needle) ] );
   while ( (node != (struct Node *)NULL)
	&& ((*compare)(needle, node) != 0) )
      node = node->next;
   return node;
}

/* enter( hashtable, newnode, hash() ) */
struct Node *enter(
   struct Node *table[],
   struct Node *node,
   int (*hash)(struct Node *) )
{
   int bucket;

   bucket = (*hash)( node );
   node->next = table[bucket];
   table[bucket] = node;
   return node;
}

struct Node *
start_search(/* hash table */
	     struct Node **table,
	     /* search context to be initialized */
	     struct SearchContext *context,
	     /* criterion function */
	     int (*criterion)(struct Node *) )
{
#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "starting search in table %p with context %p and criterion %p\n",
	  table, context, criterion);
#endif
  context->table = table;
  context->bucket = -1;
  context->node = 0;
  context->criterion = criterion;
  return next_node(context);
}

struct Node *next_node(struct SearchContext *context) /* search context */
{
  while(1) {
    if(context->node && context->node->next)
      context->node = context->node->next;
    else
      if(++(context->bucket) >= HASHSIZE) {
#ifdef DEBUG_SEARCH
	fprintf(stderr,
		"finished search with context %p\n",
		context);
#endif
	return 0;
      } else
	context->node = context->table[context->bucket];
    if(context->node)
      if(context->criterion(context->node))
	return context->node;
  }
}

int any_node(struct Node *node) {
#ifdef DEBUG_SEARCH
  fprintf(stderr, __FUNCTION__ ": %s meets the criterion.\n",
	  node->word);
#endif
  return 1;
}

int extern_node(struct Node *node) {
  if((node->refcnt) || (node->nlist.n_type & SMOKE16_N_EXT)) {
#ifdef DEBUG_SEARCH
    fprintf(stderr, __FUNCTION__ ": %s meets the criterion.\n",
	    node->word);
#endif
    return 1;
  }
#ifdef DEBUG_SEARCH
  fprintf(stderr, __FUNCTION__ ": %s doesn't meet the criterion.\n",
	  node->word);
#endif
  return 0;
}

int common_node(struct Node *node) {
  if((node->nlist.n_type & SMOKE16_N_TYPE) == SMOKE16__N_COMM) {
#ifdef DEBUG_SEARCH
    fprintf(stderr, __FUNCTION__ ": %s meets the criterion.\n",
	    node->word);
#endif
    return 1;
  }
#ifdef DEBUG_SEARCH
  fprintf(stderr, __FUNCTION__ ": %s doesn't meet the criterion.\n",
	  node->word);
#endif
  return 0;
}
