/********************************************************************
 *                                                                  *
 *      CRISP - Custom Reduced Instruction Set Programmers Editor   *
 *                                                                  *
 *      (C) Paul Fox, 1989                                          *
 *                                                                  *
 *                                                                  *
 *    Please See COPYLEFT notice.                                   *
 *                                                                  *
 ********************************************************************/
# include	"crisp.h"

int	searching_fwd = TRUE;	/* Set to direction of last search.	*/
int	translating_fwd = TRUE;	/* Direction of last translate.		*/
int	search__wrap = FALSE;	/* TRUE if search wraps around at end of */
				/* buffer, e.g. like vi.		 */
int	search__regexp = TRUE;
int	search__case = TRUE;
int	search__block = FALSE;
int	search__syntax = re_syntax();
int	search__flags;		/* Base flags to pass to re_search() and */
				/* re_translate().			 */

extern string	search__pattern;
extern string	translate__pattern;
extern string	translate__replacement;
void
main()
{
	setup_search_flags();
}
string
get_case_sensitive()
{
	return search__case ? "yes" : "no";
}
void
setup_search_flags()
{
	search__flags = 0;
	if (search__regexp == 0)
		search__flags |= SF_NOT_REGEXP;
	if (search__case == 0)
		search__flags |= SF_IGNORE_CASE;
	if (search__block)
		search__flags |= SF_BLOCK;
	if (search__syntax)
		search__flags |= SF_UNIX;
	re_syntax(search__syntax);
}
/**********************************************************************/
/*   Macro  to  hilite a group of characters until a key is pressed.  */
/*   Used by search-fwd and search-back macros.			      */
/**********************************************************************/
int
search_hilite(int match_len)
{
	int	ch;
	
	if (match_len <= 2)
		return match_len;

	/*----------------------------------------
	/*   If search is successful, hilite the
	/*   matched string but only if the matched
	/*   string len is at least 2 chars wide,
	/*   otherwise we have real problems on
	/*   a mono screen. We hilite the
	/*   string until the user presses another
	/*   key.
	/*----------------------------------------*/
	next_char(match_len - 1);
	drop_anchor(MK_NONINC);
	prev_char(match_len - 1);
	refresh();
	while ((ch = read_char()) == -1)
		;
	push_back(ch);
	raise_anchor();
	return match_len;
}
list search_options_list = {
		"Regular Expressions   : ", {"No", "Yes"},
		"Case sensitive        : ", {"No", "Yes"},
		"Block selection       : ", {"Off", "On"},
		"Syntax mode           : ", {"CRISP", "Unix"}
		};
void
search_options()
{
	list	r_list;

	r_list[0] = search__regexp;
	r_list[1] = search__case;
	r_list[2] = search__block;
	r_list[3] = search__syntax;
	
	r_list = field_list("Search Parameters", r_list, search_options_list);
	search__regexp = r_list[0];
	search__case = r_list[1];
	search__block = r_list[2];
	search__syntax = r_list[3];
	
	setup_search_flags();
}
void
translate__fwd()
{
	int	old_msg_level;

	translating_fwd = TRUE;
	if (get_parm(NULL, translate__pattern, "Translate: ", NULL, translate__pattern) <= 0)
		return;
	if (translate__pattern == "")
		return;
	if (get_parm(NULL, translate__replacement, "Replacement: ", NULL, translate__replacement) <= 0)
		return;
	old_msg_level = inq_msg_level();
	set_msg_level(0);
	re_translate(search__flags | SF_PROMPT, translate__pattern,
		translate__replacement);
	set_msg_level(old_msg_level);
}
void
translate__back()
{
	int	old_msg_level;

	translating_fwd = FALSE;
	if (get_parm(NULL, translate__pattern, "Translate back: ", NULL, translate__pattern) <= 0)
		return;
	if (translate__pattern == "")
		return;
	if (get_parm(NULL, translate__replacement, "Replacement: ", NULL, translate__replacement) <= 0)
		return;
	old_msg_level = inq_msg_level();
	set_msg_level(0);
	re_translate(search__flags | SF_PROMPT | SF_BACKWARDS, translate__pattern,
		translate__replacement);
	set_msg_level(old_msg_level);
}
/**********************************************************************/
/*   Function to apply a translate again.			      */
/**********************************************************************/
void
translate_again()
{	int	old_msg_level;

	if (translate__pattern == "") {
		error("No previous translate pattern.");
		return;
		}
	old_msg_level = inq_msg_level();
	set_msg_level(0);
	re_translate(search__flags | SF_PROMPT | (translating_fwd ? 0 : SF_BACKWARDS), 
		translate__pattern,
		translate__replacement);
	set_msg_level(old_msg_level);
}
void
search__fwd()
{	int	old_msg_level,
		match_len;
	
	if (get_parm(NULL, search__pattern, "Search for: ", NULL, search__pattern) <= 0)
		return;
	searching_fwd = TRUE;
	old_msg_level = inq_msg_level();
	set_msg_level(0);
	match_len = re_search(search__flags, search__pattern);
	set_msg_level(old_msg_level);
	search_hilite(match_len);
}
void
search__back()
{	int	old_msg_level,
		match_len;
	
	if (get_parm(NULL, search__pattern, "Search back: ", NULL, search__pattern) <= 0)
		return;
	searching_fwd = FALSE;
	old_msg_level = inq_msg_level();
	set_msg_level(0);
	match_len = re_search(SF_BACKWARDS | search__flags, search__pattern);
	set_msg_level(old_msg_level);
	search_hilite(match_len);
}

void
search_next()
{	int	old_msg_level,
		match_len;

	if (search__pattern == "") {
		error("No previous search string.");
		return;
		}

	save_position();
	next_char(searching_fwd ? 1 : -1);
	old_msg_level = inq_msg_level();
	set_msg_level(0);

	if (searching_fwd)
		match_len = re_search(search__flags, search__pattern);
	else
		match_len = re_search(SF_BACKWARDS | search__flags, search__pattern);

	if (match_len <= 0)
		restore_position();
	else
		restore_position(0);

	set_msg_level(old_msg_level);
	search_hilite(match_len);
}
void
search_prev()
{	int	old_msg_level,
		match_len;

	save_position();
	prev_char();
	old_msg_level = inq_msg_level();
	set_msg_level(0);

	match_len = re_search(SF_BACKWARDS | search__flags, search__pattern);
	if (match_len <= 0)
		restore_position();
	else
		restore_position(0);

	set_msg_level(old_msg_level);
	search_hilite(match_len);
}
/**********************************************************************/
/*   Function  callable  to  toggle  or  set  the regular expression  */
/*   character.							      */
/**********************************************************************/
void
toggle_re()
{
	search__regexp = !search__regexp;
	message("Regular expressions %s.",
		search__regexp ? "on" : "off");
	setup_search_flags();
}
/**********************************************************************/
/*   Toggle whether searches are case sensitive or not.		      */
/**********************************************************************/
void
toggle_re_case()
{
	search__case = !search__case;
	message("Case sensitivity %s.",
		search__case ? "on" : "off");
	setup_search_flags();
}

/**********************************************************************/
/*   Intelligent  search  macro.  Searches for text as user types it  */
/*   in.  Needs  to  handle  command line editing on its own, so its  */
/*   very simple.						      */
/*   								      */
/*   <Backspace> can  be  used  to delete characters that were typed  */
/*   in  and  backup  the search. Hit <Enter> to accept the entry or  */
/*   <Alt-S> to go to next entry. Hit <Esc> to abort the search.      */
/**********************************************************************/
void
i_search()
{	string	pat;
	int	ch;
	int	aborted = FALSE;
	int	save_level = 1;
	string	mac;
		
	save_position();
	while (1) {
		refresh();
		message("I-search for: %s...", pat);
		ch = read_char();
		if (ch == key_to_int("<Enter>")) {
			message("");
			break;
			}
		if (ch == key_to_int("<Esc>")) {
			message("Search aborted.");
			aborted = TRUE;
			break;
			}
		if (ch == key_to_int("<Backspace>")) {
			pat = substr(pat, 1, strlen(pat) - 1);
			if (save_level > 1) {
				restore_position();
				if (--save_level == 0) {
					save_position();
					save_level = 1;
					}
				}
			continue;
			}
		mac = inq_assignment(ch);
		if (substr(mac, 1, 6) == "search") {
			save_level++;
			save_position();
			next_char();
			if (re_search(search__flags | SF_NOT_REGEXP, pat) <= 0) {
				beep();
				save_level--;
				restore_position();
				}
			continue;
			}
		else if (mac == "undo") {
			if (save_level > 1) {
				restore_position();
				if (--save_level == 0) {
					save_position();
					save_level = 1;
					}
				}
			continue;
			}
		else {
			/***********************************************/
			/*   Add character to pattern.		       */
			/***********************************************/
			sprintf(pat, "%s%c", pat, ch);
			}
		/***********************************************/
		/*   Ok, so look for the next occurence.       */
		/***********************************************/
		save_level++;
		save_position();
		if (re_search(search__flags | SF_NOT_REGEXP, pat) <= 0) {
			/***********************************************/
			/*   If  search  fails  tell  user  and strip  */
			/*   off the nasty character.		       */
			/***********************************************/
			beep();
			pat = substr(pat, 1, strlen(pat) - 1);
			save_level--;
			restore_position();
			}
		}
	while (save_level-- > 0)
		restore_position(0);
	refresh();
}
