/* fv is a binary file editor written by Chris Hooper (cdh@mtu.edu)
 *	on 6-2-91 and has gone through many revisions since then.
 *      Much inspiration was given by Bill Moore, the first real user!
 *
 *   Author:  CHRISTOPHER D HOOPER
 *
 *   fv source Copyright (c) 1992 - 1998  Chris Hooper
 *
 *   Modification and redistribution is strictly prohibited.
 *   Sale of this software above media cost is prohibited.
 *
 *   Except for above two restrictions, this software may be used for
 *       any purpose, commercial or private.
 *
 *   Disclaimer:  This product is fit for no use, foreign or domestic.
 *                Use implies knowledge you intend to destroy something.
 */

#include <stdio.h>
#include <signal.h>
#include <curses.h>
#include <string.h>

#include "main.h"
#include "io.h"
#include "screen.h"

#ifdef LINT
#	include "lint.h"
#endif

#define MAX_HEX 8
int local_search[MAX_HEX];
int stopping = 0;

extern int status_line;

int generic_search();
void sigint();

int find_hex(start)
ulong start;
{
	char	ch;
	char	str[MAXLEN];
	int	index;
	int	index2;
	int	temp;
	int	temp2;
	int	abort = 0;
	char	search_for[MAXLEN];
	WINDOW	*jump_window;

	search_for[0] = '\0';

	stopping = 0;

	if (global_direction)
	    ch = '<';
	else
	    ch = '>';

	(void) sprintf(out_string, "%c Hex to find:", ch);
	ch = ' ';

	xrefresh(status_window);
	xrefresh(main_window);

	jump_window = xnewwin(1, COLS - 25, status_line, 20);
	xmove(jump_window, 0, 0);
	xclrtoeol(jump_window);
	xaddstr(jump_window, out_string);
	xrefresh(jump_window);

	for (index = 0; index < MAXLEN; index++)
	    str[index] = '\0';

	index = 0;
	while ((ch != 13) && !stopping) {	/* ^M */
	    xmove(jump_window, 0, 15);
	    xaddstr(jump_window, str);
	    xrefresh(jump_window);
	    ch = get_key();

	    if ((ch >= 'A') && (ch <= 'F'))
			ch += 'a' - 'A';

	    switch (ch) {
		case 13:	/* ^M - CR - end input */
		case 10:	/* ^J - LF */
#ifdef STRICT_VI
		case 27:	/* ESC */
#endif
		    ch = 13;
		    break;
		case 8: 	/* ^H - erase */
		case 127:	/* ^? */
		    if (index > 0) {
			if (str[index] == '.')
			    str[--index] = ' ';
			str[--index] = ' ';
			xmove(jump_window, 0, 15);
			xaddstr(jump_window, str);
			str[index] = '\0';
		    }
#ifdef STRICT_VI
		    else {
			abort = 1;
			ch = 13;	/* ^M */
		    }
#endif
		    break;
		case 21:	/* ^U - erase line */
		    index = 0;
		    str[index] = '\0';
		    xmove(jump_window, 0, 0);
		    xaddstr(jump_window, out_string);
		    xclrtoeol(jump_window);
		    break;
		case 24:	/* ^X - terminate input */
		case 3: 	/* ^C */
#ifndef STRICT_VI
		case 27:	/* ESC */
#endif
		    index = 0;
		    ch = 13;	/* ^M */
		    abort = 1;
		    break;
		case 22:	/* ^V - verbose next character */
		    str[index++] = get_key();
		    break;
		case '.':
		    if ((index < MAX_HEX * 2) && !(index & 1)) {
			str[index++] = '.';
			str[index++] = '.';
		    }
		    break;
		default:
		    if ((index < MAX_HEX * 2) &&
			    (((ch >= '0') && (ch <= '9')) ||
			     ((ch >= 'a') && (ch <= 'f'))))
				str[index++] = ch;
		    break;
	    }
	}
	xmove(jump_window, 0, 0);
	xclrtoeol(jump_window);
	xrefresh(jump_window);

	xdelwin(jump_window);

	if (abort)
	    return(start);

	str[index] = '\0';
	if (index > 0) {
	    global_type = 1;
	    if (index & 1) {
		index++;
		temp = str[0];
		for (index2 = 1; index2 < index; index2++) {
		    temp2 = str[index2];
		    str[index2] = temp;
		    temp = temp2;
		}
		str[index2] = temp;
		str[0] = '0';
	    }

	    global_num = index / 2;
	    out_string[0] = '\0';

	    for (index2 = 0; index2 < global_num; index2++) {
		if ((str[2 * index2] == '.') || (str[2 * index2 + 1] == '.'))
		    global_special[index] = 1;
		else {
		    sscanf(str + (2 * index2), "%02x", &local_search[index2]);
		    global_special[index] = 0;
		}
		sprintf(out_string, "%02x", local_search[index2]);
		strcat(search_for, out_string);
		global_search[index2] = (char) local_search[index2];
	    }
	    return(generic_search(start));
	}
	else
#ifdef STRICT_VI
	    return(generic_search(start));
#else
	    return(start);
#endif
}

int find_str(start)
ulong start;
{
	char	ch;
	char	str[MAXLEN];
	int	index;
	char	out_string[256];
	int	abort = 0;

	stopping = 0;

	if (!noscreen)
		leaveok(status_window, FALSE);

	xrefresh(status_window);
	xrefresh(main_window);

	if (global_direction)
		ch = '<';
	else
		ch = '>';

	(void) sprintf(out_string, "%c String to find:", ch);
	ch = ' ';

	xmove(status_window, 0, 20);
	xclrtoeol(status_window);
	xaddstr(status_window, out_string);
	xrefresh(status_window);

	for (index = 0; index < MAXLEN; index++)
		str[index] = '\0';

	index = 0;
	while ((ch != 13) && !stopping) {
	    xmove(status_window, 0, 38);
	    xaddstr(status_window, str);
	    xrefresh(status_window);
	    ch = get_key();
	    switch (ch) {
		case 10:	/* ^J - LF */
		case 13:	/* ^M - CR */
#ifdef STRICT_VI
		case 27:	/* ESC - Escape */
#endif
		    ch = 13;
		    break;
		case 8:		/* ^H - delete character */
		case 127:	/* ^? */
		    if (index > 0) {
			index -= 1;
			str[index] = ' ';		/* whiteout char */
			xmove(status_window, 0, 38);	/* redraw string */
			xaddstr(status_window, str);
			str[index] = '\0';
		    }
#ifdef STRICT_VI
		    else {
			abort = 1;
			ch = 13;
		    }
#endif
		    break;
		case 21:	/* ^U - erase input line */
		    index = 0;
		    str[index] = '\0';
		    xmove(status_window, 0, 20);
		    xaddstr(status_window, out_string);
		    xclrtoeol(status_window);
		    break;
		case 22:	/* ^V - verbose next character */
		    str[index++] = get_key();
		    break;
		case 24: 	/* ^X */
		case 3: 	/* ^C */
#ifndef STRICT_VI
		case 27:	/* ESC */
#endif
		    index = 0;
		    ch = 13;
		    abort = 1;
		    break;
		default:
		    str[index++] = ch;
	    }
	}

	/* ^C typed */
	if (stopping)
		abort = 1;

	str[index] = '\0';

	if (!noscreen) {
	    xmove(status_window, 0, 20);
	    xclrtoeol(status_window);
	    xrefresh(status_window);

	    leaveok(status_window, TRUE);
	}

	if (abort)
	    return(start);

	if (index > 0) {
	    global_type	 = 0;
	    global_num	 = index;
	    (void) strcpy((char *) global_search, str);
	    for (index=0; index < global_num; index++)
		if (str[index] == '.')
		    global_special[index] = 1;
		else
		    global_special[index] = 0;
	    return(generic_search(start));
	}
	else
#ifdef STRICT_VI
	    return(generic_search(start));
#else
	    return(start);
#endif
}

/* This is the search routine for all forward and backward searches.
	Buffer is moved less the full size of the thing we are searching
	for in order to make sure it isn't split between a block.
*/
int generic_search(start)
ulong start;
{
	int	index;
	long	retval = start;
	int 	wrapped = 0;
	long	cur_pos;	/* initialized below */
	long	buf_last;	/* initialized below */
	char 	cdir;		/* initialized below */
	char	search_for[MAXLEN];
	register uchar first_char; /* first search character */

	stopping = 0;
	first_char = global_search[0];

	if (global_num == 0)
		return(start);

#if !defined(Dynix) && !defined(Linux) && !defined(FreeBSD) && !defined(HPUX)
	if (!noscreen)
	noraw();
#	if defined(Solaris2)
	cbreak();
#	endif
#endif

	status_range(start, start);

	if (global_type) {
	    (void) sprintf(search_for, "0x%02x", local_search[0]);
	    for (index = 1; index < global_num; index++)
	        if (global_special[index])
	            strcat(search_for, "??");
	        else {
	            (void) sprintf(out_string, "%02x", local_search[index]);
	            strcat(search_for, out_string);
	        }
	} else
	    (void) sprintf(search_for, "\"%s\"", global_search);

	if (global_direction)
		cdir = '<';
	else
		cdir = '>';
	sprintf(out_string, " %c for %s", cdir, search_for);
	xmove(status_window, 0, 20);
	xaddstr(status_window, "Searching");
	xaddstr(status_window, out_string);
	xclrtoeol(status_window);
	xrefresh(status_window);

	if (!prompting)
		return(start);

	if (global_direction) {  /* Backward Search */
	    buf_last = start - max_buf_size;
	    if (buf_last < 0) {
		buf_last += fend;
		xmove(status_window, 0, 20);
		xaddstr(status_window, "Search Wrapping");
		xaddstr(status_window, out_string);
		xclrtoeol(status_window);
		xrefresh(status_window);
	    }
	    ALIGN(buf_last);

	    buf_read(buf_last, buffer, max_buf_size);

	    cur_pos = ALIGNED(max_buf_size - global_num + alignment);
	    while (!stopping) {
		nope:
		if (cur_pos < alignment) {
		    status_range(buf_last, start);

		    buf_last -= ALIGNED(max_buf_size - global_num);

		    if (wrapped && (buf_last <= start - max_buf_size))
			break;

		    buf_read(buf_last, buffer, max_buf_size);

		    if (buf_last < 0) {
			buf_last += ALIGNED(fend);
			wrapped = 1;
			xmove(status_window, 0, 20);
			xaddstr(status_window, "Search Wrapping");
			xaddstr(status_window, out_string);
			xclrtoeol(status_window);
			xrefresh(status_window);
		    }
		    cur_pos = ALIGNED(max_buf_size - global_num);
		} else
		    cur_pos -= alignment;
		if (first_char == buffer[cur_pos]) {
		    for (index = 1; index < global_num; index++)
			if ((global_search[index] != buffer[cur_pos + index]) &&
			   !(global_special[index]))
			    goto nope;
		    stopping = 1;
		    retval = cur_pos + buf_last;
		    if (retval > fend - alignment) {
			retval -= fend;
			ALIGN(retval);
		    }
		    if (retval > start)
			wrapped = 1;
		    else
			wrapped = 0;
		    break;
		}
	    }
	} else {   /* Forward Search */
	    buf_last = start;

	    buf_read(buf_last, buffer, max_buf_size);
/*	    cur_pos = 4; */
	    cur_pos = 0;

	    while (!stopping) {
		nope2:
		if (cur_pos > (max_buf_size - global_num)) {
		    status_range(buf_last, start);

		    cur_pos = 0;
		    buf_last += ALIGNED(max_buf_size - global_num);

		    if (wrapped && (buf_last >= start))
			break;

		    if (buf_last >= fend) {
			buf_last = 0;
			wrapped = 1;
			xmove(status_window, 0, 20);
			xaddstr(status_window, "Search Wrapping");
			xaddstr(status_window, out_string);
			xclrtoeol(status_window);
			xrefresh(status_window);
		    }

		    buf_read(buf_last, buffer, max_buf_size);
		} else
		    cur_pos += alignment;

		if (first_char == buffer[cur_pos]) {
		    for (index = 1; index < global_num; index++)
			if ((global_search[index] != buffer[cur_pos + index]) &&
			   !(global_special[index]))
			    goto nope2;
		    retval = cur_pos + buf_last;
		    if (retval > fend - alignment) {
			retval -= fend;
			ALIGN(retval);
		    }
		    if (retval < start)
			wrapped = 1;
		    else
			wrapped = 0;
		    break;
		}
	    }

	}

	daddr = -1;
	xmove(status_window, 0, 20);
	if (retval == start) {
	    if (wrapped)
		xaddstr(status_window, "Search Failed");
	    else
		xaddstr(status_window, "Search failed");
	    xaddstr(status_window, out_string);
	} else if (wrapped) {
	    xaddstr(status_window, "Search Wrapped");
	    xaddstr(status_window, out_string);
	}
	xclrtoeol(status_window);
	xrefresh(status_window);
	return(retval);
}
