/*
    Clif - A C-like Interpreter Framework
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997 T. Hruz, L. Koren

    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.

*/

/*
 * remote_call.c
 *
 * Maintenance functions for calling remote functions.
 */ 

#include <stdio.h>

#include "allocx.h"
#include "printfx.h"
#include "global.h"
#include "intrinsic.h"
#include "load.c"
#include "remote_call.h"

static int hash_code_remote PROTO((char *));
static void putstruct_remote PROTO((struct remote_has_tab *, char *, int));
/* Looks up the hash table of remote functions. */
static struct remote_has_tab *lookup_remote PROTO((char *s));


/* \verbatim{remote_call_c_hastab_remote.tex} */

struct remote_has_tab *hastab_remote;

/* \verbatim */

static int remote_offset_counter = 0; /* Counter for remote function */
				      /* offset. */

/*
 * Checks the table if a function is in. 
 * If not it saves all needed information.
 */
void 
has_remote (x)         
  struct remote_tab *x;
{
  struct remote_has_tab *np, *arch;
  while (x != NULL)
    {
      if (NULL == lookup_remote (x->name))
				/* The function is not in the table. */
	{
#ifdef DEBUG
	  printfx("Including new remote function\n");
	  printfx("hash code:%u\n",hash_code_remote(x->name)); 
#endif
	  f[remote_offset_counter] = (INTRINSIC_FUNCTION)x->adr;
	  np = hastab_remote + hash_code_remote (x->name);
	  if(np->name == NULL)           /* There is no list. */
	    {
	      putstruct_remote (np, x->name, remote_offset_counter);
	      x = x->next;
	      remote_offset_counter++;
	    }
	  else                         /* There is a list. */
	    {
	      do       
		{  	
		  arch=np;
		  np=np->next;	
		}
	      while(np != NULL);	
	      np = (struct remote_has_tab *) allocate (sizeof(struct
							      remote_has_tab), PERM);
	      arch->next = np;
	      putstruct_remote (np, x->name, remote_offset_counter);
	      x = x->next;
	      remote_offset_counter++;
	    }
	  arch = NULL;
	}
      else                                  /* The function is in the table. */
	{
	  error_message (1006);
	}
    }
}

/*
 * Saves useful information about functions
 * and connect the information with the
 * function name.
 */
static void 
putstruct_remote (np, name, i)
  struct remote_has_tab *np;
  char *name;
  int i;
{
  np->name = name;
#ifdef DEBUG
  printfx("function's name %s is stored\n",np->name);
#endif
  np->offset = i;
#ifdef DEBUG
  printfx("offset:%u is in table\n",np->offset);
#endif
}

/*
 * Looks up the hash table of remote functions.
 */
static struct remote_has_tab *
lookup_remote (s)
  char *s;
{
  struct remote_has_tab *ps;

  ps = hastab_remote + hash_code_remote (s);
  if(*(int *)ps == 0)
    return(NULL);
 
  while ((ps->name != s) && (ps->next != NULL))
    ps = ps->next;
  if ((ps->next == NULL) && (ps->name != s))
    return (NULL);
  else 
    return (ps); 
}
 
/*
 * Hash function.
 */
static int 
hash_code_remote (s)
  char *s;
{
  int c = 0;
  while(*s)
    {
      c = c<<1^(*s);
      s++;
    }
  if (c<0) 
    c = (-c);
  return (c % SIZE_REMOTE);
}
