/*
 * csh - a shell by PJAC
 * hash.c - command hashing routines
 */

#include "csh.h"

#ifdef	MSDOS
#include "ndir.h"
#else
#include <sys/types.h>
#include <dir.h>
#endif

do_rehash(argc, argv)
char	**argv;
{
	clr_hash();
	bld_hash();
	return(OK);
}

#define	H_TABSIZ	97	/* a good prime */

int	h_tab[H_TABSIZ];

/*
 * build the hash tables
 */

bld_hash()
{
	char	lbuf[128];
	char	*p, *q;
	DIR	*dirp;
	struct	direct	*d;
	int	hash;
	int	dnumb = 0;

	if(!Path)
		return;
	for(p = Path; *p;){
#ifdef	MSDOS
		for(q = lbuf ; *p && *p != ';' ; *q++ = *p++);
#else
		for(q = lbuf ; *p && *p != ':' ; *q++ = *p++);
#endif
		if(*p)
			p++;
		if(q == lbuf || *lbuf == '.')
			continue;
		*q = 0;
		dirp = opendir(lbuf);
		if(dirp != 0){
			while(d = readdir(dirp)){
				if(*d->d_name == '.')
					continue;
				hash = b_hash(d->d_name);
				add_hash(dnumb, hash);
			}
			closedir(dirp);
		}
		dnumb++;
	}
}

/*
 * return a hash number for a name
 */

b_hash(name)
char	*name;
{
	int	hash = 0;
	int	c;

	while(*name && *name != '.'){
		c = *name++;
		if(c >= 'a' && c <= 'z')
			c += 'A' - 'a';
		hash = (hash * 27 ) + (c - 'A');
	}
	if(hash < 0)
		hash = -hash;
	return(hash);
}

/*
 * look for hash in directory dnumb
 */

h_look(dnumb, hash)
{
	if(dnumb >= sizeof(h_tab[0]) * 8)   /* if more than 16 dirs give in */
		return(1);
	return( (h_tab[hash % H_TABSIZ] & (1<<dnumb)) != 0);
}

/*
 * add file with hash 'hash' to directory 'dnumb'
 */

add_hash(dnumb, hash)
{
	if(dnumb >= sizeof(h_tab[0]) * 8)
		return;
	h_tab[hash % H_TABSIZ] |= (1<<dnumb);
}

/*
 * clear the hash tables
 */

clr_hash()
{
	int	*p;

	for(p = h_tab ; p < &h_tab[H_TABSIZ] ; p++)
		*p = 0;
}
