%
%  forward and backward search functions.  These functions can search across
%  lines.
%
define search_across_lines (str, dir)
{
   variable n, s, s1, fun;

   fun = &fsearch;
   if (dir < 0) fun = &bsearch;

   n = is_substr (str, "\n");

   !if (n) return fun(str);
   
   s = substr (str, 1, n);
   s1 = substr (str, n + 1, strlen(str));
   n = strlen(s);
   
   push_mark ();
   
   while (fun(s))
     {
	% we are matched at end of the line.
	go_right (n);
	if (looking_at(s1)) 
	  {
	     go_left(n);
	     pop_mark(0);
	     return 1;
	  }
	if (dir < 0) go_left (n);
     }
   pop_mark(1);
   0;
}


define search_maybe_again (str, dir)
{
   variable ch;
   while (search_across_lines (str, dir))
     {
	if (EXECUTING_MACRO or DEFINING_MACRO) return 1;
	
	message ("Press RET to continue searching.");
	update (1);
	ch = getkey ();
	if (ch != '\r')
	  {
	     ungetkey (ch);
	     return 1;
	  }
	if (dir > 0) go_right (1);
     }
   return 0;
}

define search_forward ()
{
   variable str, not_found;

   % if (MINIBUFFER_ACTIVE) return;   % the second statement makes this unnecessary
   str = read_mini("Search forward:", LAST_SEARCH, Null_String);
   !if (strlen(str)) return;
   
   push_mark ();
   if (looking_at(str)) go_right(1);
   
   save_search_string (str);
   not_found = not (search_maybe_again (str, 1));
   pop_mark (not_found);
   
   if (not_found) error ("Not found.");
}

define search_backward ()
{
   variable str;
   
   % if (MINIBUFFER_ACTIVE) return;
   str = read_mini("Search backward:", LAST_SEARCH, Null_String);
   !if (strlen(str)) return;
   
   save_search_string (str);
   !if (search_maybe_again (str, -1)) error ("Not found.");
}


define replace_do_replace (str, len)
{
   push_mark ();
   go_right(len);
   del_region ();
   insert (str);
}

define replace_maybe_query (pat, rep, query)
{
   variable n, prompt, doit, err, ch, len;
   variable last, last_ok = 0;

   ERROR_BLOCK 
     {
	if (last_ok) pop_mark (0);
     }
   
   len = strlen (pat);
   
   prompt =  Sprintf ("Replace '%s' with '%s'? (y/n/!/+/q/h)", pat, rep, 2);
   
   while (n = search_across_lines(pat, 1), n)
     {
	!if (query)
	  {
	     replace_do_replace (rep, len);
	     continue;
	  }

	do 
	  {
	     message(prompt);
	     update (0);
	     % regexp_mark_pattern(n);  this might be nice 
	
	     ch = getkey ();
	     if (ch == 'r')
	       {
		  recenter (window_info('r') / 2);
		  go_left(n);
	       }
	     
	  } while (ch == 'r');
	
	switch(ch)
	  { case 'u' and last_ok:
	     pop_mark (1); push_spot ();
	     replace_do_replace (last, strlen(rep));
	     pop_spot ();
	     last_ok = 0;
	  }   
	  { case 'y' :
	     if (last_ok) pop_mark (0); last_ok = 1;
	     push_spot(); push_mark ();
	     go_right (len); last = bufsubstr ();
	     pop_spot (); push_mark ();
	     replace_do_replace(rep, len);
	  }
	  { case 'n' : go_right(1);}
	  { case '+' : replace_do_replace(rep, len);
	               break;
	  }
	  { case '!' :
	     do 
	       {
		  replace_do_replace (rep, len);
	       }
	     while(search_across_lines(pat, 1));
	  }
          { case 'q' : break; }
          {  pop();
	     flush ("y:replace, n:skip, !:replace all, u: undo last, +:replace then quit, q:quit");
	     input_pending (30); pop ();
	  }
     }
   EXECUTE_ERROR_BLOCK;
}

define replace_cmd ()
{
   variable pat, prompt, rep;
   
   pat = read_mini("Replace:", Null_String, Null_String);
   !if (strlen (pat)) return;
   
   prompt = strcat (strcat ("Replace '", pat), "' with:");
   rep = read_mini(prompt, Null_String, Null_String);
   replace_maybe_query (pat, rep, 1);
   message ("done.");   
}