/*
 * search.c - dictionary search routines.
 *
 * David A. Curry
 * Purdue University
 * Engineering Computer Network
 * April, 1986
 *
 * $Log:	search.c,v $
 * Revision 1.7  91/07/09  00:14:23  ambar
 * changed location of inclusion of stdio.h
 * 
 * Revision 1.6  90/10/21  18:42:29  ambar
 * changed to use dbm instead of ndbm (for !#$#% lusing 4.2 based ultrix)
 * 
 * Revision 1.5  88/02/25  22:48:06  ambar
 * changed the location of our header files; made inclusion
 * of sunrpcweb.h dependent on -DSUNRPC.
 * 
 * Revision 1.4  88/02/20  07:02:23  ambar
 * ifdef'ed for SUNRPC
 * 
 * Revision 1.3  87/06/16  23:41:07  jtkohl
 * bcopy arguments backward
 * 
 * Revision 1.2  87/06/16  22:37:43  jtkohl
 * Pointer alignment problems.  Don't cast it, but copy it.
 * 
 * Revision 1.1  87/06/16  20:26:11  jtkohl
 * Initial revision
 * 
 * Revision 1.2  86/12/26  22:02:59  davy
 * Changed to work with DBM files.
 * 
 */
#ifndef lint
static char rcsid_search_c[] = "$Header: /afs/sipb.mit.edu/project/sipbsrc/src/webster/src/server/RCS/search.c,v 1.7 91/07/09 00:14:23 ambar Exp $";
#endif

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <dbm.h>
#include <syslog.h>
#include <index.h>
#include <webster.h>
#ifdef SUNRPC
#include <sunrpcweb.h>
#endif SUNRPC

extern FILE *indexfp;		/* index file pointer		*/
extern struct header hdr;	/* index file header		*/

int nanswers = 0;			/* number of answers found	*/
int answers_valid = 0;			/* non-zero if numbers valid	*/
struct answer answers[MAXANSWERS];	/* answers we find		*/

/*
 * adjust - try to adjust the bounds of the search to only those words
 *	    that start with the same first character as the word we
 *	    are looking for.
 */
adjust(word, low, high)
char *word;
daddr_t *low, *high;
{
	int x;

	if (isalpha(*word)) {
		*low = hdr.h_starts[SUBSCRIPT(*word)];
		*high = (*word == 'z' ? hdr.h_idxsize
			 : hdr.h_starts[SUBSCRIPT((*word) + 1)]);
	}
	else if (isdigit(*word)) {
		*low = hdr.h_starts[SUBSCRIPT(*word)];
		*high = hdr.h_starts[(*word == '9' ? SUBSCRIPT('a')
				      : SUBSCRIPT((*word) + 1))];
	}
	else if (*word == '-') {
		*low = hdr.h_starts[SUBSCRIPT('-')];
		*high = hdr.h_starts[SUBSCRIPT('0')];
	}
	else if (*word == '\'') {
		*low = hdr.h_starts[SUBSCRIPT('\'')];
		*high = hdr.h_starts[SUBSCRIPT('-')];
	}
	else {
		*low = 0;
		*high = hdr.h_idxsize;
	}

	if (*low > *high) {
		x = *low;
		*low = *high;
		*high = x;
	}
}

/*
 * easysearch - simple binary search
 */
easysearch(word, start)
char *word;
int start;
{
	datum key, content;

	nanswers = start;

	key.dptr = word;
	key.dsize = strlen(word);

	content = fetch(key);
	if (content.dptr != (char *) NULL) {
		(void) strcpy(answers[nanswers].a_word, word);
		bcopy(content.dptr, (char *)&answers[nanswers].a_idx,
		      sizeof(struct index));

		answers[nanswers].a_idxok = 1;
		nanswers++;
	}
}

/*
 * wildsearch - handle limited regular expressions - ONECH matches a single
 *		character, MANYCH matches zero or more characters.
 */
#ifdef SUNRPC
char *
#endif SUNRPC
wildsearch(word, start)
char *word;
int start;
{
	char buf[BUFSIZ];
	register int len;
	daddr_t addr, low, high;

	/*
	 * Adjust our search field.
	 */
	nanswers = start;
	adjust(word, &low, &high);

	/*
	 * Seek to first word.
	 */
	addr = low;
	if (fseek(indexfp, low, 0) == -1) {
#ifdef SUNRPC
		return(error(0, "Couldn't find word\n", (char *) NULL));
#else !SUNRPC
		error(0, "Couldn't find word\n", (char *) NULL);
		return(-1);
#endif SUNRPC
	}
	/*
	 * Look for words.
	 */
	while ((addr <= high) && (fgets(buf, BUFSIZ, indexfp) != NULL)) {
		len = strlen(buf);

		addr += len;
		buf[len - 1] = NULL;

		if (match1(buf, word)) {
			(void) strcpy(answers[nanswers].a_word, buf);
			answers[nanswers].a_idxok = 0;
			nanswers++;
		}

		if (nanswers >= MAXANSWERS)
#ifdef SUNRPC
			return((char *) NULL);
#else !SUNRPC
		        return;
#endif SUNRPC
	}
#ifdef SUNRPC
	return((char *) NULL);
#endif SUNRPC
}

match1(s, t)
register char *s, *t;
{
	register short c, x;

	if (x = *s++) {
		if ((x &= 0177) == 0)
			x = 0200;
	}

	switch (c = *t++) {
	default:
		if (c != x)
			return(0);
	case ONECH:
		if (x)
			return(match1(s, t));
		return(0);
	case MANYCH:
		return(match2(--s, t));
	case NULL:
		return(!x);
	}
}

match2(s, t)
register char *s, *t;
{
	if (*t == NULL)
		return(1);

	while (*s) {
		if (match1(s++, t))
			return(1);
	}

	return(0);
}
