/*
**      extern.c - External module related routines
**
**
** Copyright (c) 1996,97  Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
**
*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "lite.h"

#ifdef HAVE_DLFCN_H
#  include <dlfcn.h>
#endif

#define	NUM_HASH	16

fbucket_t **fHash = NULL;
static	char errBuf[240];
static 	int externInit;
static	int stripLeader;
extern	sym_t *externReturn;

int calcHash(s)
        char *s;
{
        int     hash=0;
        char    *cp;

        cp = s;
        while(*cp)
        {
                hash += *cp++;
        }
        hash = hash & (NUM_HASH - 1);
        return(hash);
}




void addExterns(functs)
        efunct_t *functs;
{
        efunct_t *cur;
        int     hash;
        fbucket_t *new;

        if (!externInit)
        {
                externInit=1;
                fHash = (fbucket_t **) malloc(sizeof(void *) * NUM_HASH);
		bzero(fHash,NUM_HASH * sizeof(void*));
        }
        cur = functs;
        while(cur->name)
        {
                hash = calcHash(cur->name);
                new = (fbucket_t *)malloc(sizeof(fbucket_t));
                (void)bzero(new,sizeof(fbucket_t));
                new->funct = cur;
                if (fHash[hash])
                {
                        new->next = fHash[hash];
                }
                fHash[hash] = new;
                cur++;
        }
}



efunct_t *findExtern(funct)
	char	*funct;
{
        fbucket_t       *curBucket;
        efunct_t *extFunct;

        curBucket = fHash[calcHash(funct)];
        while(curBucket)
        {
                extFunct = curBucket->funct;
                if (strcmp(funct,extFunct->name) == 0)
                {
			return(extFunct);
		}
		curBucket = curBucket->next;
	}
	return(NULL);
}


void setError(msg)
	char *msg;
{
	sym_t	*sym;

	sym = symGetSymbol("$ERRMSG");
	if (!sym)
	{
		sym = symCreateSymbol("$ERRMSG",TYPE_CHAR, SCALAR);
	}
	if (sym->val)
		free(sym->val);
	sym->val = (char *)strdup(msg);
	sym->length = strlen(msg);
}




typedef struct objHash_s {
	char	*obj;
	u_int	id;
	struct	objHash_s *next;
} objHash_t;

typedef struct objStack_s {
	u_int	id;
	struct	objStack_s *next;
} objStack_t;


static 	objHash_t 	*objHash[NUM_HASH];
static	u_int		curID = 1;
static	objStack_t	*objStack = NULL;

u_int storeObject(obj)
	char	*obj;
{
	objStack_t	*curStk;
	objHash_t	*curHash,
			*curBucket;
	u_int		id;
	static	int	init=0;
	

	if (!init)
	{
		(void)bzero(objHash, sizeof(objHash));
		init++;
	}

	/*
	** Grab an ID for this thing
	*/
	if (objStack)
	{
		curStk = objStack;
		objStack = objStack->next;
		id = curStk->id;
		(void)free(curStk);
	}
	else
	{
		if (curID == 0)
		{
			return(0);
		}
		id = curID++;
	}

	/*
	** Store the pointer in the hashTable
	*/
	curBucket = objHash[id % NUM_HASH];
	curHash = (objHash_t *)malloc(sizeof(objHash_t));
	if (!curHash)
	{
		return(0);
	}
	(void)bzero(curHash,sizeof(objHash_t));
	curHash->id = id;
	curHash->obj = obj;
	if (curBucket)
	{
		curHash->next = curBucket;
	}
	objHash[id % NUM_HASH] = curHash;
	return(id);
}

char *fetchObject(id)
	u_int	id;
{
	objHash_t       *curHash;

	curHash = objHash[id % NUM_HASH];
	while(curHash)
	{
		if (curHash->id == id)
		{
			return(curHash->obj);
		}
		curHash = curHash->next;
	}
	return(NULL);
}



char *deleteObject(id)
	u_int	id;
{
	objHash_t       *curHash,
			*prevHash;
	objStack_t	*curStk;
	char		*obj;

	curHash = objHash[id % NUM_HASH];
	prevHash = NULL;
	while(curHash)
	{
		if (curHash->id == id)
		{
			if (prevHash)
			{
				prevHash->next = curHash->next;
			}
			else
			{
				objHash[id %NUM_HASH] = curHash->next;
			}
			obj = curHash->obj;
			(void)free(curHash);
			curStk = (objStack_t*)malloc(sizeof(objStack_t));
			(void)bzero(curStk,sizeof(objStack_t));
			curStk->id = id;
			curStk->next = objStack;
			objStack = curStk;
			return(obj);
		}
		curHash = curHash->next;
	}
	return(NULL);
}


#if defined(HAVE_DYNAMIC) && defined(HAVE_DLFCN_H)

int modLoadModule(module)
	char	*module;
{
	char	path[255],
		tmp[255];
	void	*modPtr;
	int	(*init)();
	

	externReturn = NULL; /* force a symbol ref for extern return */
	strcpy(tmp,module+1);
	tmp[strlen(tmp) -1] = 0;
	sprintf(path,"%s/modules/%s.so",INST_DIR,tmp);
	modPtr = dlopen(path,1);
	if (modPtr == NULL)
	{
		sprintf(errBuf,"\ndlopen : %s", dlerror());
		perror(errBuf);
		return(-1);
	}
	init = (int(*)())dlsym(modPtr,"_init_mod");
	if (!init)
	{
		init = (int(*)())dlsym(modPtr,"init_mod");
		if (!init)
		{
			perror("dlsym");
			return(-1);
		}
		stripLeader = 1;
	}
	if ((*init)(modPtr) < 0)
		return(-1);
	else
		return(0);
}


int modLoadModuleFunctions(modPtr, functs)
	void	*modPtr;
        efunct_t *functs;
{
        efunct_t *cur;
        int     hash;
        fbucket_t       *new;
	char		*cp;

        if (!externInit)
        {
                externInit=1;
                fHash = (fbucket_t **) malloc(sizeof(void *) * NUM_HASH);
		bzero(fHash,NUM_HASH * sizeof(void*));
        }
        cur = functs;
        while(cur->name)
        {
		cp = cur->functName;
		if (stripLeader)
			cp++;
		cur->funct = (void(*)())dlsym(modPtr,cp);
		if (!cur->funct)
		{
			sprintf(errBuf,"Can't load module symbol '%s'",
				cur->functName);
			parseError(errBuf);
			return(-1);
		}
                hash = calcHash(cur->name);
                new = (fbucket_t *)malloc(sizeof(fbucket_t));
                (void)bzero(new,sizeof(fbucket_t));
                new->funct = cur;
                if (fHash[hash])
                {
                        new->next = fHash[hash];
                }
                fHash[hash] = new;
                cur++;
        }
	return(0);
}

#endif
