/*
 *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *	This will be free software, but only when it is finished.
 */

/* LINTLIBRARY */

#include "hostenv.h"
#include "mailer.h"
#include <ctype.h>
#include <sys/file.h>
#include "search.h"

/*
 * Binary search of a file for keyword-value pairs.
 */

struct conscell *
search_bin(sip)
	struct search_info *sip;
{
	FILE *fp;
	register unsigned char *cp, *s;
	register int c;
	long int top, bot, mid;
	int i, retry, symid;
	struct conscell *tmp;
	struct spblk *spl;
	char buf[BUFSIZ];
	extern FILE *fpmap();
	extern int deferit, cistrcmp();
	extern void v_set();

	if (sip->file == NULL)
		return NULL;
	retry = 0;
	symid = symbol((u_char *)sip->file);
	spl = sp_lookup(symid, spt_files);
	if (spl == NULL || (fp = (FILE *)spl->data) == NULL) {
reopen:
		fp = fopen(sip->file, "r");
		if (fp == NULL) {
			++deferit;
			v_set(DEFER, DEFER_IO_ERROR);
			(void) fprintf(stderr, "search_bin: cannot open %s!\n",
						sip->file);
			return NULL;
		}
		if (spl == NULL)
			sp_install(symid, (u_char *)fp, DESC_FILEP, spt_files);
		else
			spl->data = (u_char *)fp;
	}
	bot = 0;
	(void) fseek(fp, 0L, 2);
	top = ftell(fp);
	for(;;) {
		mid = (top + bot)/2;
		fseek(fp, mid, 0);
		do {
			c = getc(fp);
			mid++;
		} while (!ferror(fp) && c != EOF && c != '\n');
		if (fgets(buf, sizeof buf, fp) == NULL) {
			if (!retry && ferror(fp)) {
				(void) fclose(fp);
				++retry;
				goto reopen;
			}
			break;
		}
		for (cp = (unsigned char *)buf; *cp; ++cp)
			if (!isascii(*cp) || isspace(*cp))
				break;
		if (*cp == '\0')
			*(cp+1) = '\0';
		else
			*cp = '\0';
		i = cistrcmp((char *)(sip->key), buf);
		if (i < 0) {
			if(top <= mid)
				break;
			top = mid;
		} else if (i == 0) {
			for (++cp; *cp; ++cp)
				if (isascii(*cp) && !isspace(*cp))
					break;
			for (s = cp; *s != '\0'; ++s)
				if (!isascii(*s) || isspace(*s))
					break;
			return newstring((u_char *)strnsave((char *)cp, s - cp));
		} else
			bot = mid;
	}
	fseek(fp, bot, 0);
	while (ftell(fp) < top) {
		if (fgets(buf, sizeof buf, fp) == NULL)
			return NULL;
		for (cp = (unsigned char *)buf; *cp; ++cp)
			if (!isascii(*cp) || isspace(*cp))
				break;
		if (*cp == '\0')
			*(cp+1) = '\0';
		else
			*cp = '\0';
		i = cistrcmp((char *)(sip->key), buf);
		if (i < 0)
			return NULL;
		else if (i == 0) {
			for (++cp; *cp; ++cp)
				if (isascii(*cp) && !isspace(*cp))
					break;
			for (s = cp; *s != '\0'; ++s)
				if (!isascii(*s) || isspace(*s))
					break;
			return newstring((u_char *)strnsave((char *)cp, s - cp));
		}
	}
	return NULL;
}

