talker/
talker/bin/
talker/files/whois/
talker/update/
talker/update/bin/
/*
 * editor.c
 */

#include <memory.h>
#include <stdlib.h>

#include "config.h"
#include "player.h"
#include "fix.h"

/* externs */

extern struct command editor_list[];
extern char    *end_string(), *next_space();
extern int     strnomatch(char *, char *, int);

/* interns */

void            editor_main();

/* print out some stats */

void            edit_stats(player * p, char *str)
{
   int             words = 0, lines = 0, blip = 0;
   char           *scan, *oldstack;
   oldstack = stack;
   for (scan = p->edit_info->buffer; *scan; scan++)
   {
      switch (*scan)
      {
    case ' ':
       if (blip)
          words++;
       blip = 0;
       break;
    case '\n':
       if (blip)
          words++;
       blip = 0;
       lines++;
       break;
    default:
       blip = 1;
      }
   }
   sprintf(oldstack, " Used %d bytes out of %d, in %d lines and %d words.\n",
           p->edit_info->size, p->edit_info->max_size, lines, words);
   stack = end_string(stack);
   tell_player(p, oldstack);
   stack = oldstack;
}

/* view the entire buffer */

void            edit_view(player * p, char *str)
{
   tell_player(p, p->edit_info->buffer);
}

/* insert a line into the buffer */

void            insert_line(player * p, char *str)
{
   ed_info        *e;
   int             len;
   char           *from, *to, *oldstack;
   e = p->edit_info;

   oldstack = stack;
   sprintf(stack, "%s\n", str);

   len = strlen(oldstack);
   if ((len + e->size) >= (e->max_size))
   {
      tell_player(p, " Line too long to fit into buffer.\n");
      return;
   }
   from = e->buffer + e->size;
   to = from + len;
   while (from != e->current)
      *(--to) = *(--from);
   *(--to) = *(--from);
   e->size += len;
   for (; len; len--)
      *(e->current)++ = *stack++;
   *stack++ = 0;
   tell_player(p, oldstack);
   stack = oldstack;
}


/* save and restore important flags that the editor changes */

void            save_flags(player * p)
{
   if (!p->edit_info)
      return;
   p->edit_info->flag_copy = p->flags;
   p->edit_info->sflag_copy = p->system_flags;
   p->edit_info->tflag_copy = p->tag_flags;
   p->edit_info->cflag_copy = p->custom_flags;
   p->edit_info->mflag_copy = p->misc_flags;
   p->edit_info->input_copy = p->input_to_fn;
   p->flags &= ~PROMPT;
   if (p->custom_flags & QUIET_EDIT)
      p->tag_flags |= BLOCK_TELLS | BLOCK_SHOUT;
   p->input_to_fn = editor_main;
}

void            restore_flags(player * p)
{
   if (!p->edit_info)
      return;
   p->flags = p->edit_info->flag_copy;
   p->system_flags = p->edit_info->sflag_copy;
   p->tag_flags = p->edit_info->tflag_copy;
   p->custom_flags = p->edit_info->cflag_copy;
   p->misc_flags = p->edit_info->mflag_copy;
   p->input_to_fn = p->edit_info->input_copy;
}


/* the main editor function */

void            editor_main(player * p, char *str)
{
   if (!p->edit_info)
   {
      log("error", "Editor called with no edit_info");
      return;
   }
   if (*str == '/')
   {
      restore_flags(p);
      match_commands(p, str + 1);
      save_flags(p);
      return;
   }
   if (*str == '.')
   {
      sub_command(p, str + 1, editor_list);
      if (p->edit_info)
    do_prompt(p, "+");
      return;
   }
   insert_line(p, str);
   do_prompt(p, "+");
}


/* fire editor up */

void            start_edit(player * p, int max_size, void *finish_func, void *quit_func,
                            char *current)
{
   ed_info        *e;
   int             old_length;
   if (p->edit_info)
      return;
   e = (ed_info *) MALLOC(sizeof(ed_info));
   memset(e, 0, sizeof(ed_info));
   p->edit_info = e;
   e->buffer = (char *) MALLOC(max_size);
   memset(e->buffer, 0, max_size);
   e->max_size = max_size;
   e->finish_func = finish_func;
   e->quit_func = quit_func;
   if (current)
   {
      old_length = strlen(current);
      memcpy(e->buffer, current, old_length);
      e->size = old_length + 1;
   } else
      e->size = 1;
   e->current = e->buffer + e->size - 1;
   p->flags |= DONT_CHECK_PIPE;
   save_flags(p);
   tell_player(p, " Entering editor ... Use /help editor for help.\n"
                  " /<command> for general commands, .<command> for editor "
                  "commands\n"
                  " Use '.end' to finish and keep edit\n");
   if (p->custom_flags & QUIET_EDIT)
      tell_player(p, " Blocking shouts and tells whilst in editor.\n");
   edit_view(p, 0);
   edit_stats(p, 0);
   do_prompt(p, "+");
}

/* tie up any loose ends */

void            finish_edit(player * p)
{
   if (!(p->edit_info))
      return;
   restore_flags(p);
   if (p->edit_info->buffer)
      FREE(p->edit_info->buffer);
   FREE(p->edit_info);
   p->edit_info = 0;
   p->flags &= ~DONT_CHECK_PIPE;
}

/* editor functions */

/* finish editing without changes */

void            edit_quit(player * p, char *str)
{
   void            (*fn) ();
   fn = p->edit_info->quit_func;
   (*fn) (p);
   finish_edit(p);
}

/* finish editing with changes */

void            edit_end(player * p, char *str)
{
   void            (*fn) ();
   fn = p->edit_info->finish_func;
   (*fn) (p);
   finish_edit(p);
}

/* clean the buffer completely */

void            edit_wipe(player * p, char *str)
{
   ed_info        *e;
   e = p->edit_info;
   memset(e->buffer, 0, e->size);
   e->size = 1;
   e->current = e->buffer;
   tell_player(p, " Edit buffer completely wiped ...\n");
}

/* view the current line */

void            edit_view_line(player * p, char *str)
{
   char           *scan, *oldstack;
   oldstack = stack;
   scan = p->edit_info->current;
   while (*scan && *scan != '\n')
      *stack++ = *scan++;
   *stack++ = '\n';
   *stack++ = 0;
   tell_player(p, oldstack);
   stack = oldstack;
}

/* move back up a line */

void            edit_back_line(player * p, char *str)
{
   char           *c;
   ed_info        *e;
   e = p->edit_info;
   c = e->current;
   if (c == e->buffer)
   {
      tell_player(p, " Can't go back any more, top of buffer.\n");
      return;
   }
   c -= 2;
   while (c != e->buffer && *c != '\n')
      c--;
   if (c == e->buffer)
      tell_player(p, " Reached top of buffer.\n");
   else
      c++;
   e->current = c;
   edit_view_line(p, 0);
}

/* move forward a line */

void            edit_forward_line(player * p, char *str)
{
   char           *c;
   ed_info        *e;
   e = p->edit_info;
   c = e->current;
   if (!*c)
   {
      tell_player(p, " Can't go forward, bottom of buffer.\n");
      return;
   }
   while (*c && *c != '\n')
      c++;
   if (*c)
      c++;
   e->current = c;
   if (!*c)
      tell_player(p, " Reached bottom of buffer.\n");
   else
      edit_view_line(p, 0);
}

/* print out available commands */

void            edit_view_commands(player * p, char *str)
{
   view_sub_commands(p, editor_list);
}

/* move to bottom of buffer */

void            edit_goto_top(player * p, char *str)
{
   p->edit_info->current = p->edit_info->buffer;
   tell_player(p, " Top of buffer.\n");
}

/* move to top of buffer */

void            edit_goto_bottom(player * p, char *str)
{
   p->edit_info->current = p->edit_info->buffer + p->edit_info->size - 1;
   tell_player(p, " Bottom of buffer.\n");
}

/* delete the current line */

void            edit_delete_line(player * p, char *str)
{
   ed_info        *e;
   char           *sl, *el;
   int            do_list = 1, i;

   if (*str)
	do_list = atoi(str);

 if (do_list < 0) {
	tell_player(p, " Format: .del <num lines - default is 1>\n");
	return;
 }
	

 for (i = 0; i < do_list; i++) {
   e = p->edit_info;
   sl = e->current;
   if (!*sl)
   {
      tell_player(p, " End of buffer, no line to delete.\n");
      return;
   }
   for (el = sl; (*el && *el != '\n'); el++)
      e->size--;
   if (*el)
   {
      el++;
      e->size--;
   }
   while (*el)
      *sl++ = *el++;
   while (sl != el)
      *sl++ = 0;
 }
 if (i > 1)
   tell_player(p, " Lines deleted.\n");
 else
   tell_player(p, " Line deleted.\n");
}


/* go to a specific line */

void            edit_goto_line(player * p, char *str)
{
   char           *scan;
   int             line = 0;
   line = atoi(str);
   if (line < 1)
   {
      tell_player(p, " Argument is a number greater than zero.\n");
      return;
   }
   for (line--, scan = p->edit_info->buffer; (*scan && line); scan++)
      if (*scan == '\n')
    line--;
   if (!*scan)
   {
      tell_player(p, " Not that many lines.\n");
      return;
   }
   p->edit_info->current = scan;
   edit_view_line(p, 0);
}


/* toggle whether someone goes into quiet mode on edit */

void            toggle_quiet_edit(player * p, char *str)
{
   restore_flags(p);
   if (!strcasecmp("off", str))
      p->custom_flags &= ~QUIET_EDIT;
   else if (!strcasecmp("on", str))
      p->custom_flags |= QUIET_EDIT;
   else
      p->custom_flags ^= QUIET_EDIT;

   if (p->custom_flags & QUIET_EDIT)
      tell_player(p, " You will block tells and shouts upon editing.\n");
   else
      tell_player(p, " You won't block shouts and tells on editing.\n");
   save_flags(p);
}


/* the dreaded pager B-)  */

int             draw_page(player * p, char *text)
{
   int             end_line = 0, n;
   ed_info        *e;
   char           *oldstack;
   float	  pdone;
   oldstack = stack;

   for (n = TERM_LINES + 1; n; n--, end_line++)
   {
      while (*text && *text != '\n')
         *stack++ = *text++;
      if (!*text)
         break;
      *stack++ = *text++;
   }
   *stack++ = 0;
   tell_player(p, oldstack);
   if (*text && p->edit_info)
   {
      e = p->edit_info;
      end_line += e->size;
      pdone = ((float) end_line / (float) e->max_size) * 100;
      sprintf(oldstack, 
              "[Pager: %d-%d (%d) [%.0f%%] Tap <return> to continue, or q to quit]"
	      "\n",e->size, end_line, e->max_size, pdone);
      stack = end_string(oldstack);
      do_prompt(p, oldstack);
   }
   stack = oldstack;
   return *text;
}

void            quit_pager(player * p, ed_info * e)
{
   p->input_to_fn = e->input_copy;
   p->flags = e->flag_copy;
   if (e->buffer)
      FREE(e->buffer);
   FREE(e);
   p->edit_info = 0;
}

void            back_page(player * p, ed_info * e)
{
   char           *scan;
   int             n;
   scan = e->current;
   for (n = TERM_LINES + 1; n; n--)
   {
      while (scan != e->buffer && *scan != '\n')
    scan--;
      if (scan == e->buffer)
    break;
      e->size--;
      scan--;
   }
   e->current = scan;
}

void            forward_page(player * p, ed_info * e)
{
   char           *scan;
   int             n;
   scan = e->current;
   for (n = TERM_LINES + 1; n; n--)
   {
      while (*scan && *scan != '\n')
    scan++;
      if (!*scan)
    break;
      e->size++;
      scan++;
   }
   e->current = scan;
}

void            pager_fn(player * p, char *str)
{
   ed_info        *e;
   e = p->edit_info;
   switch (tolower(*str))
   {
      case 'b':
    back_page(p, e);
    break;
      case 'p':
    back_page(p, e);
    break;
      case 0:
    forward_page(p, e);
    break;
      case 'f':
    forward_page(p, e);
    break;
      case 'n':
    forward_page(p, e);
    break;
      case 't':
    e->current = e->buffer;
    e->size = 0;
    draw_page(p, e->current);
    break;
      case 'q':
    quit_pager(p, e);
    return;
   }
   if (!draw_page(p, e->current))
      quit_pager(p, e);
}


void            pager(player * p, char *text, int page)
{
   ed_info        *e;
   int             length = 0, lines = 0;
   char           *scan;

   if (p->custom_flags & NO_PAGER && !page)
   {
      tell_player(p, text);
      return;
   }
   if (p->edit_info)
   {
      tell_player(p, " Eeek, can't enter pager right now.\n");
      return;
   }
   for (scan = text; *scan; scan++, length++)
   {
      if (*scan == '\n')
      {
         lines++;
      }
      length++;
   }
   if (lines > (TERM_LINES + 1))
   {
      e = (ed_info *) MALLOC(sizeof(ed_info));
      memset(e, 0, sizeof(ed_info));
      p->edit_info = e;
      e->buffer = (char *) MALLOC(length);
      memcpy(e->buffer, text, length);
      e->current = e->buffer;
      e->max_size = lines;
      e->size = 0;
      e->input_copy = p->input_to_fn;
      e->flag_copy = p->flags;
      p->input_to_fn = pager_fn;
      p->flags &= ~PROMPT;
   }
   draw_page(p, text);
}


void editor_search_string(player * p, char *str) {

	ed_info *e;
	char *this_line, *this_word;
	int x = 0;
	char *oldstack;

	if (!*str) {
		tell_player(p, " Format: .s <search string>\n");
		return;
		}

	e = p->edit_info;
	this_line = e->current;

	for (this_word = e->current; *this_word && !x; this_word++) {
		if (*this_word == '\n')
			this_line = this_word + 1;
                if (!((isspace(*(this_word-1)) && !(isspace(*this_word))))) 
			;
		else if (!strnomatch(str,this_word, 1))
			x = 1;
	}
 
	if (!x) {
		tell_player(p, " String not found before end of buffer reached.\n");
		return;
		}
	else {
		p->edit_info->current = this_line;
		edit_view_line(p, 0);
		}
}	
 		
int countquote(char *str) {
	int cnt = 0;

	while (*str) {
		if (*str == '\"')
			cnt++;
		str++;
		}
	return cnt;
}

void   edit_search_and_replace(player * p, char *str) {

	ed_info  *e;
	char      buff[10000], search[50], replace[50], *holder, *oldstack;
	int       b = 0, cnt = 0, s=0, r=0;

       	if (countquote(str) != 4)
		{
		tell_player(p, " Format: .sr \"search\" \"replace\"\n");
		return;
		}
 
	for (b=0; b < 10000; b++)
		buff[b] = 0;
	b=0;
	e = p->edit_info;
	for (s=0; s < 50; s++)
	{
        search[s] = 0;
	replace[s] = 0;
	}
	s=0;
	while (*str && *str != '\"') 
		str++;
	str++;
	while (*str && *str != '\"') {
	     if (s < 50)
		search[s++] = *str++;
	     else
		str++;
		}	
	str++;
	while (*str && *str != '\"') 
		str++;
	str++;
	while (*str && *str != '\"') {
	     if (r < 50)	
		replace[r++] = *str++;
	     else
		str++;     
	}

	for (holder = e->buffer; (*holder && b < 10000); holder++)	{
		
		if (strnomatch(search, holder, 1))
			buff[b++] = *holder;
		else {
			cnt++;
			r = 0;
			s = 0;
			while (replace[r] && b < 10000)
				buff[b++] = replace[r++];
			while (search[s] && *holder && search[s]==*holder) {
				holder++;	
				s++;
			}
			holder--;
			/* if (*holder && b < 10000)
				buff[b++] = *holder; */
		}
	}

	/* will this work?! guess so.. */
	strncpy(e->buffer, buff, e->max_size);

	if (cnt) {
	oldstack = stack;
	if (cnt != 1)
		sprintf(stack, " %d replacements made.\n", cnt);	
	else
		strcpy(stack, " One replacement made.\n");
	stack = end_string(stack);
	tell_player(p, oldstack);
	e->current = e->buffer;
	stack = oldstack;
	}
	else 
		tell_player(p, " No changes made.\n");

}