/*
 * input.c: does the actual input line stuff... keeps the appropriate stuff
 * on the input line, handles insert/delete of characters/words... the whole
 * ball o wax 
 *
 * Written By Michael Sandrof
 *
 * Copyright(c) 1990 
 *
 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
 */

#if 0
static	char	rcsid[] = "@(#)$Id: input.c,v 1.9 1994/07/03 08:23:47 mrg Exp $";
#endif

#include "irc.h"

#include "alias.h"
#include "edit.h"
#include "exec.h"
#include "history.h"
#include "hook.h"
#include "input.h"
#include "ircaux.h"
#include "keys.h"
#include "screen.h"
#include "server.h"
#include "term.h"
#include "translat.h"
#include "vars.h"
#include "window.h"

const int WIDTH = 10;

/* input_prompt: contains the current, unexpanded input prompt */
static	char	*input_prompt = (char *) 0;

/* input_line: the actual screen line where the input goes */
static	int	input_line;

/* str_start: position in buffer of first visible character in the input line */
static	int	str_start = 0;

/* These are sanity macros.  The file was completely unreadable before 
 * i put these in here.  I make no apologies for them.
 */
#define INPUT_BUFFER current_screen->input_buffer
#define MIN_POS current_screen->buffer_min_pos
#define THIS_POS current_screen->buffer_pos
#define THIS_CHAR INPUT_BUFFER[THIS_POS]
#define MIN_CHAR INPUT_BUFFER[MIN_POS]
#define PREV_CHAR INPUT_BUFFER[THIS_POS-1]
#define NEXT_CHAR INPUT_BUFFER[THIS_POS+1]
#define ADD_TO_INPUT(x) strmcat(INPUT_BUFFER, (x), INPUT_BUFFER_SIZE);
#define INPUT_VISIBLE INPUT_BUFFER[str_start]

/*
 * upper_mark and lower_mark: marks the upper and lower positions in the
 * input buffer which will cause the input display to switch to the next or
 * previous bunch of text 
 */
static	int	lower_mark;
static	int	upper_mark;

/* zone: the amount of editable visible text on the screen */
static	int	zone;

/* cursor: position of the cursor in the input line on the screen */
static	int	cursor = 0;

/* cursor_to_input: move the cursor to the input line, if not there already */
extern void cursor_to_input _((void))
{
	Screen *old_current_screen;

	old_current_screen = current_screen;
	for (current_screen = screen_list; current_screen; current_screen = current_screen->next)
	{
		if (current_screen->alive && is_cursor_in_display(NULL))
		{
			term_move_cursor(cursor, input_line);
			cursor_not_in_display();
			term_flush();
		}
	}
	set_current_screen(old_current_screen);
}

/*
 * update_input: does varying amount of updating on the input line depending
 * upon the position of the cursor and the update flag.  If the cursor has
 * move toward one of the edge boundaries on the screen, update_cursor()
 * flips the input line to the next (previous) line of text. The update flag
 * may be: 
 *
 * NO_UPDATE - only do the above bounds checking. 
 *
 * UPDATE_JUST_CURSOR - do bounds checking and position cursor where is should
 * be. 
 *
 * UPDATE_FROM_CURSOR - does all of the above, and makes sure everything from
 * the cursor to the right edge of the screen is current (by redrawing it). 
 *
 * UPDATE_ALL - redraws the entire line 
 */
#ifdef __STDC__
extern void	update_input (int update)
#else
extern void update_input(update)
	int	update;
#endif
{
	int	old_start;
	static	int	co = 0,
			li = 0;
	char	*ptr;
	int	len,
		free_it = 1,
		cnt,
		max;
	char	*prompt;

	if (dumb)
		return;
	cursor_to_input();

	if (current_screen->promptlist)
		prompt = current_screen->promptlist->prompt;
	else
		prompt = input_prompt;

	if (prompt)
	{
		if (update != NO_UPDATE)
		{
			char	*inp_ptr = (char *) 0;
			int	args_used;	/* this isn't used here but is
						 * passed to expand_alias()
						 */
			if (is_process(get_target_by_refnum(0)))
			{
				ptr = (char *)get_prompt_by_refnum(0);
				free_it = 0;
			}
			else
				ptr = expand_alias((char *) 0, prompt, empty_string, &args_used, NULL);

			if (*ptr && ((my_strnicmp(ptr, "Password:", 9) == 0) || (my_strnicmp(ptr, "Operator Password:",18) == 0) ||
					(my_strnicmp(ptr, "Server Password:", 16) == 0)))
				term_echo(0);
			else
				term_echo(1);

			len = strlen(ptr);

			if (strncmp(ptr, INPUT_BUFFER, len) || !len)
			{
				malloc_strcpy(&inp_ptr, INPUT_BUFFER + MIN_POS);
				strmcpy(INPUT_BUFFER, ptr, INPUT_BUFFER_SIZE);
				THIS_POS += (len - MIN_POS);
				MIN_POS = strlen(ptr);
				ADD_TO_INPUT(inp_ptr);
				new_free(&inp_ptr);
				update = UPDATE_ALL;
			}

			if (free_it)
				new_free(&ptr);
		}
	}
	else
		term_echo(1);

	if ((li != LI) || (co != CO))
	{
		/* resized?  Keep it simple and reset everything */
		input_line = LI - 1;
		zone = CO - (WIDTH * 2);
		lower_mark = WIDTH;
		upper_mark = CO - WIDTH;
		cursor = MIN_POS;
		THIS_POS = MIN_POS;
		str_start = 0;
		li = LI;
		co = CO;
	}
	old_start = str_start;
	while ((THIS_POS < lower_mark) && lower_mark > WIDTH)
	{
		upper_mark = lower_mark;
		lower_mark -= zone;
		str_start -= zone;
	}
	while (THIS_POS >= upper_mark)
	{
		lower_mark = upper_mark;
		upper_mark += zone;
		str_start += zone;
	}
	cursor = THIS_POS - str_start;
	if ((old_start != str_start) || (update == UPDATE_ALL))
	{
		term_move_cursor(0, input_line);
		if ((str_start == 0) && (MIN_POS > 0))
		{
			int	echo;

			echo = term_echo(1);
			if (MIN_POS > (CO - WIDTH))
				len = CO - WIDTH - 1;
			else
				len = MIN_POS;
			cnt = term_puts(&(INPUT_VISIBLE), len);
			term_echo(echo);
			cnt += term_puts(&(INPUT_BUFFER[str_start + len]), CO - len);
		}
		else
			cnt = term_puts(&(INPUT_VISIBLE), CO);
		if (term_clear_to_eol())
			term_space_erase(cnt);
		term_move_cursor(cursor, input_line);
	}
	else if (update == UPDATE_FROM_CURSOR)
	{
		term_move_cursor(cursor, input_line);
		cnt = cursor;
		max = CO - (THIS_POS - str_start);
		if ((len = strlen(&(THIS_CHAR))) > max)
			len = max;
		cnt += term_puts(&(THIS_CHAR), len);
		if (term_clear_to_eol())
			term_space_erase(cnt);
		term_move_cursor(cursor, input_line);
	}
	else if (update == UPDATE_JUST_CURSOR)
		term_move_cursor(cursor, input_line);
	term_flush();
}

#ifdef __STDC__
extern void change_input_prompt (int direction)
#else
extern void change_input_prompt(direction)
	int	direction;
#endif
{
	if (!current_screen->promptlist)
	{
		strcpy(INPUT_BUFFER, current_screen->saved_input_buffer);
		THIS_POS = current_screen->saved_buffer_pos;
		MIN_POS = current_screen->saved_min_buffer_pos;
		*current_screen->saved_input_buffer = '\0';
		current_screen->saved_buffer_pos = 0;
		current_screen->saved_min_buffer_pos = 0;
		update_input(UPDATE_ALL);
	}

	else if (direction == -1)
		update_input(UPDATE_ALL);

	else if (!current_screen->promptlist->next)
	{
		strcpy(current_screen->saved_input_buffer, INPUT_BUFFER);
		current_screen->saved_buffer_pos = THIS_POS;
		current_screen->saved_min_buffer_pos = MIN_POS;
		*INPUT_BUFFER = '\0';
		THIS_POS = MIN_POS = 0;
		update_input(UPDATE_ALL);
	}
}

/* input_move_cursor: moves the cursor left or right... got it? */
#ifdef __STDC__
extern void	input_move_cursor (int dir)
#else
extern void input_move_cursor(dir)
	int	dir;
#endif
{
	cursor_to_input();
	if (dir)
	{
		if (THIS_CHAR)
		{
			THIS_POS++;
			if (term_cursor_right())
				term_move_cursor(cursor + 1, input_line);
		}
	}
	else
	{
		if (THIS_POS > MIN_POS)
		{
			THIS_POS--;
			if (term_cursor_left())
				term_move_cursor(cursor - 1, input_line);
		}
	}
	update_input(NO_UPDATE);
}

/*
 * set_input: sets the input buffer to the given string, discarding whatever
 * was in the input buffer before 
 */
#ifdef __STDC__
void	set_input (char *str)
#else
void set_input(str)
	char	*str;
#endif
{
	strmcpy(INPUT_BUFFER + MIN_POS, str, INPUT_BUFFER_SIZE - MIN_POS);
	THIS_POS = strlen(INPUT_BUFFER);
}

/*
 * get_input: returns a pointer to the input buffer.  Changing this will
 * actually change the input buffer.  This is a bad way to change the input
 * buffer tho, cause no bounds checking won't be done 
 */
char	*get_input _((void))
{
	return (&(MIN_CHAR));
}

/* init_input: initialized the input buffer by clearing it out */
extern void init_input _((void))
{
	*INPUT_BUFFER = (char) 0;
	THIS_POS = MIN_POS;
}

/* get_input_prompt: returns the current input_prompt */
extern char	*get_input_prompt _((void))
{ 
	return (input_prompt); 
}

/*
 * set_input_prompt: sets a prompt that will be displayed in the input
 * buffer.  This prompt cannot be backspaced over, etc.  It's a prompt.
 * Setting the prompt to null uses no prompt 
 */
#ifdef __STDC__
void	set_input_prompt (char *prompt)
#else
void set_input_prompt(prompt)
	char	*prompt;
#endif
{
	if (prompt)
	{
		if (input_prompt && !strcmp (prompt, input_prompt))
			return;
		malloc_strcpy(&input_prompt, prompt);
	}
	else
	{
		if (!input_prompt)
			return;
		malloc_strcpy(&input_prompt, empty_string);
	}
	update_input(UPDATE_ALL);
}


/* 
 * Why did i put these in this file?  I dunno.  But i do know that the ones 
 * in edit.c didnt have to be here, and i knew the ones that were here DID 
 * have to be here, so i just moved them all to here, so that they would all
 * be in the same place.  Easy enough. (jfn, june 1995)
 */

/*
 * input_forward_word: move the input cursor forward one word in the input
 * line 
 */
#ifdef __STDC__
extern void input_forward_word (char unused, char *not_used)
#else
extern void input_forward_word (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();

	while ((my_isspace(THIS_CHAR) || ispunct(THIS_CHAR)) && (THIS_CHAR))
			THIS_POS++;
	while (!(ispunct(THIS_CHAR) || my_isspace(THIS_CHAR)) && (THIS_CHAR))
			THIS_POS++;
	update_input(UPDATE_JUST_CURSOR);
}

/* input_backward_word: move the cursor left on word in the input line */
#ifdef __STDC__
extern void input_backward_word (char unused, char *not_used)
#else
extern void input_backward_word (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();
	while ((THIS_POS > MIN_POS) && (my_isspace(PREV_CHAR) || ispunct(PREV_CHAR)))
		THIS_POS--;
	while ((THIS_POS > MIN_POS) && !(ispunct(PREV_CHAR) || my_isspace(PREV_CHAR)))
		THIS_POS--;

	update_input(UPDATE_JUST_CURSOR);
}

/* input_delete_character: deletes a character from the input line */
#ifdef __STDC__
extern void input_delete_character (char unused, char *not_used)
#else
extern void input_delete_character (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();
	if (THIS_CHAR)
	{
		char	*ptr = (char *) 0;
		int	pos;

		malloc_strcpy(&ptr, &(NEXT_CHAR));
		strcpy(&(THIS_CHAR), ptr);
		new_free(&ptr);
		if (term_delete())
			update_input(UPDATE_FROM_CURSOR);
		else
		{
			pos = str_start + CO - 1;
			if (pos < strlen(INPUT_BUFFER))
			{
				term_move_cursor(CO - 1, input_line);
				term_putchar(INPUT_BUFFER[pos]);
				term_move_cursor(cursor, input_line);
			}
			update_input(NO_UPDATE);
		}
	}
}


/* input_backspace: does a backspace in the input buffer */
#ifdef __STDC__
extern void	input_backspace(char key, char *blah)
#else
extern void
input_backspace(key, blah)
	char	key;
	char 	*blah;
#endif
{
	cursor_to_input();
	if (THIS_POS > MIN_POS)
	{
		char	*ptr = (char *) 0;
		int	pos;

		malloc_strcpy(&ptr, &(THIS_CHAR));
		strcpy(&(PREV_CHAR), ptr);
		new_free(&ptr);
		THIS_POS--;
		if (term_cursor_left())
			term_move_cursor(cursor - 1, input_line);
		if (THIS_CHAR)
		{
			if (term_delete())
			{
				update_input(UPDATE_FROM_CURSOR);
				return;
			}
			else
			{
				pos = str_start + CO - 1;
				if (pos < strlen(INPUT_BUFFER))
				{
					term_move_cursor(CO - 1, input_line);
					term_putchar(INPUT_BUFFER[pos]);
				}
				update_input(UPDATE_JUST_CURSOR);
			}
		}
		else
		{
			term_putchar(' ');
			if (term_cursor_left())
				term_move_cursor(cursor - 1, input_line);
			update_input(NO_UPDATE);
		}
	}
}

/*
 * input_beginning_of_line: moves the input cursor to the first character in
 * the input buffer 
 */
#ifdef __STDC__
extern void input_beginning_of_line (char unused, char *not_used)
#else
extern void input_beginning_of_line (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();
	THIS_POS = MIN_POS;
	update_input(UPDATE_JUST_CURSOR);
}

/*
 * input_end_of_line: moves the input cursor to the last character in the
 * input buffer 
 */
#ifdef __STDC__
extern void input_end_of_line (char unused, char *not_used)
#else
extern void input_end_of_line (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();
	THIS_POS = strlen(INPUT_BUFFER);
	update_input(UPDATE_JUST_CURSOR);
}

#ifdef __STDC__
extern void input_delete_to_previous_space (char key, char *blah)
#else
extern void input_delete_to_previous_space (key, blah)
char key, *blah;
#endif
{
	int	old_pos;
	char	c;

	cursor_to_input();
	old_pos = THIS_POS;
	c = THIS_CHAR;

	while (!my_isspace(THIS_CHAR) && THIS_POS >= MIN_POS)
		THIS_POS--;

	if (THIS_POS < old_pos)
	{
		strcpy(&(NEXT_CHAR), &(INPUT_BUFFER[old_pos]));
		THIS_POS++;
	}

	update_input(UPDATE_FROM_CURSOR);
}

/*
 * input_delete_previous_word: deletes from the cursor backwards to the next
 * space character. 
 */
#ifdef __STDC__
extern void input_delete_previous_word (char unused, char *not_used)
#else
extern void input_delete_previous_word (unused, not_used)
char unused, *not_used;
#endif
{
	int	old_pos;
	char	c;

	cursor_to_input();
	old_pos = THIS_POS;
	while ((THIS_POS > MIN_POS) && (my_isspace(PREV_CHAR) || ispunct(PREV_CHAR)))
		THIS_POS--;
	while ((THIS_POS > MIN_POS) && !(ispunct(PREV_CHAR) || my_isspace(PREV_CHAR)))
		THIS_POS--;
	c = INPUT_BUFFER[old_pos];
	INPUT_BUFFER[old_pos] = (char) 0;
	malloc_strcpy(&cut_buffer, &THIS_CHAR);
	INPUT_BUFFER[old_pos] = c;
	strcpy(&(THIS_CHAR), &(INPUT_BUFFER[old_pos]));
	update_input(UPDATE_FROM_CURSOR);
}

/*
 * input_delete_next_word: deletes from the cursor to the end of the next
 * word 
 */
#ifdef __STDC__
extern void input_delete_next_word (char unused, char *not_used)
#else
extern void input_delete_next_word (unused, not_used)
char unused, *not_used;
#endif
{
	int	pos;
	char	*ptr = (char *) 0,
		c;

	cursor_to_input();
	pos = THIS_POS;
	while ((my_isspace(INPUT_BUFFER[pos]) || ispunct(INPUT_BUFFER[pos])) && INPUT_BUFFER[pos])
		pos++;
	while (!(ispunct(INPUT_BUFFER[pos]) || my_isspace(INPUT_BUFFER[pos])) && INPUT_BUFFER[pos])
		pos++;
	c = INPUT_BUFFER[pos];
	INPUT_BUFFER[pos] = (char) 0;
	malloc_strcpy(&cut_buffer, &(THIS_CHAR));
	INPUT_BUFFER[pos] = c;
	malloc_strcpy(&ptr, &(INPUT_BUFFER[pos]));
	strcpy(&(THIS_CHAR), ptr);
	new_free(&ptr);
	update_input(UPDATE_FROM_CURSOR);
}

/*
 * input_add_character: adds the character c to the input buffer, repecting
 * the current overwrite/insert mode status, etc 
 */
#ifdef __STDC__
extern void input_add_character (char c, char *unused)
#else
extern void
input_add_character(c, unused)
	char	c;
	char	*unused;
#endif
{
	int	display_flag = NO_UPDATE;

	cursor_to_input();
	if (THIS_POS < INPUT_BUFFER_SIZE)
	{
		if (get_int_var(INSERT_MODE_VAR))
		{
			if (THIS_CHAR)
			{
				char	*ptr = (char *) 0;

				malloc_strcpy(&ptr, &(THIS_CHAR));
				THIS_CHAR = c;
				NEXT_CHAR = 0;
				ADD_TO_INPUT(ptr);
				new_free(&ptr);
				if (term_insert(c))
				{
					term_putchar(c);
					if (NEXT_CHAR)
					    display_flag = UPDATE_FROM_CURSOR;
					else
					    display_flag = NO_UPDATE;
				}
			}
			else
			{
				THIS_CHAR = c;
				NEXT_CHAR = 0;
				term_putchar(c);
			}
		}
		else
		{
			if (THIS_CHAR == 0)
				NEXT_CHAR = 0;
			THIS_CHAR = c;
			term_putchar(c);
		}
		THIS_POS++;
		update_input(display_flag);
	}
}

/* input_clear_to_eol: erases from the cursor to the end of the input buffer */
#ifdef __STDC__
extern void input_clear_to_eol (char unused, char *not_used)
#else
extern void input_clear_to_eol (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();
	malloc_strcpy(&cut_buffer, &(THIS_CHAR));
	THIS_CHAR = 0;
	if (term_clear_to_eol())
	{
		term_space_erase(cursor);
		term_move_cursor(cursor, input_line);
	}
	update_input(NO_UPDATE);
}

/*
 * input_clear_to_bol: clears from the cursor to the beginning of the input
 * buffer 
 */
#ifdef __STDC__
extern void input_clear_to_bol (char unused, char *not_used)
#else
extern void input_clear_to_bol (unused, not_used)
char unused, *not_used;
#endif
{
	char	*ptr = (char *) 0;

	cursor_to_input();
	malloc_strcpy(&cut_buffer, &(MIN_CHAR));
	cut_buffer[THIS_POS - MIN_POS] = (char) 0;
	malloc_strcpy(&ptr, &(THIS_CHAR));
	MIN_CHAR = (char) 0;
	ADD_TO_INPUT(ptr);
	new_free(&ptr);
	THIS_POS = MIN_POS;
	term_move_cursor(MIN_POS, input_line);
	if (term_clear_to_eol())
	{
		term_space_erase(MIN_POS);
		term_move_cursor(MIN_POS, input_line);
	}
	update_input(UPDATE_FROM_CURSOR);
}

/*
 * input_clear_line: clears entire input line
 */
#ifdef __STDC__
extern void input_clear_line (char unused, char *not_used)
#else
extern void input_clear_line (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();
	malloc_strcpy(&cut_buffer, INPUT_BUFFER + MIN_POS);
	MIN_CHAR = (char) 0;
	THIS_POS = MIN_POS;
	term_move_cursor(MIN_POS, input_line);
	if (term_clear_to_eol())
	{
		term_space_erase(MIN_POS);
		term_move_cursor(MIN_POS, input_line);
	}
	update_input(NO_UPDATE);
}

/*
 * input_transpose_characters: swaps the positions of the two characters
 * before the cursor position 
 */
#ifdef __STDC__
extern void input_transpose_characters (char unused, char *not_used)
#else
extern void input_transpose_characters (unused, not_used)
char unused, *not_used;
#endif
{
	cursor_to_input();
	if (current_screen->buffer_pos > MIN_POS)
	{
		u_char	c1, c2;
		int	pos, end_of_line = 0;

		if (THIS_CHAR)
			pos = THIS_POS;
		else if (strlen(INPUT_BUFFER) > MIN_POS + 2)
		{
			pos = THIS_CHAR - 1;
			end_of_line = 1;
		}
		else
			return;

		c1 = INPUT_BUFFER[pos];
		c2 = INPUT_BUFFER[pos] = INPUT_BUFFER[pos - 1];
		INPUT_BUFFER[pos - 1] = c1;
		if (term_cursor_left() || (end_of_line && term_cursor_left()))
			term_move_cursor(cursor - end_of_line ? 2 : 1, input_line);
		term_putchar(c1);
		term_putchar(c2);
		if (!end_of_line && term_cursor_left())
			term_move_cursor(cursor - 1, input_line);
		update_input(NO_UPDATE);
	}
}


#ifdef __STDC__
extern void refresh_inputline (char unused, char *not_used)
#else
extern void refresh_inputline (unused, not_used)
char unused, *not_used;
#endif
{
	update_input(UPDATE_ALL);
}

/*
 * input_yank_cut_buffer: takes the contents of the cut buffer and inserts it
 * into the input line 
 */
#ifdef __STDC__
extern void input_yank_cut_buffer (char unused, char *not_used)
#else
extern void input_yank_cut_buffer (unused, not_used)
char unused, *not_used;
#endif
{
	char	*ptr = (char *) 0;

	if (cut_buffer)
	{
		malloc_strcpy(&ptr, &(THIS_CHAR));
		/* Ooops... */
		THIS_CHAR = 0;
		ADD_TO_INPUT(cut_buffer);
		ADD_TO_INPUT(ptr);
		new_free(&ptr);
		update_input(UPDATE_FROM_CURSOR);
		THIS_POS += strlen(cut_buffer);
		if (THIS_POS > INPUT_BUFFER_SIZE)
			THIS_POS = INPUT_BUFFER_SIZE;
		update_input(UPDATE_JUST_CURSOR);
	}
}


/* used with input_move_cursor */
#define RIGHT 1
#define LEFT 0

/* BIND functions: */
#ifdef __STDC__
extern void forward_character (char dumb, char *dumber)
#else
extern void forward_character (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	input_move_cursor(RIGHT);
}

#ifdef __STDC__
extern void backward_character (char dumb, char *dumber)
#else
extern void backward_character (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	input_move_cursor(LEFT);
}

#ifdef __STDC__
extern void backward_history (char dumb, char *dumber)
#else
extern void backward_history (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	get_history(PREV);
}

#ifdef __STDC__
extern void forward_history (char dumb, char *dumber)
#else
extern void forward_history (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	get_history(NEXT);
}

#ifdef __STDC__
extern void toggle_insert_mode (char dumb, char *dumber)
#else
extern void toggle_insert_mode (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	set_var_value(INSERT_MODE_VAR, "TOGGLE");
}

#ifdef __STDC__
extern void send_line (char dumb, char *dumber)
#else
extern void send_line (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	int	server;
	WaitPrompt	*OldPrompt;

	server = from_server;
	from_server = get_window_server(0);
	reset_hold((Window *) 0);
	hold_mode((Window *) 0, OFF, 1);
	if (current_screen->promptlist && current_screen->promptlist->type == WAIT_PROMPT_LINE)
	{
		OldPrompt = current_screen->promptlist;
		(*OldPrompt->func)(OldPrompt->data, get_input());
		set_input(empty_string);
		current_screen->promptlist = OldPrompt->next;
		new_free(&OldPrompt->data);
		new_free(&OldPrompt->prompt);
		new_free((char **)&OldPrompt);
		change_input_prompt(-1);
	}
	else
	{
		char	*line,
			*tmp = NULL;

		line = get_input();
		malloc_strcpy(&tmp, line);

		if (do_hook(INPUT_LIST, "%s", tmp))
		{
			if (get_int_var(INPUT_ALIASES_VAR))
				parse_line(NULL, tmp, empty_string, 1, 0);
			else
				parse_line(NULL, tmp, NULL, 1, 0);
		}
		update_input(UPDATE_ALL);
		new_free(&tmp);
	}
	from_server = server;
}



/* TOTAL lossage here */
#ifdef __STDC__
extern void meta9_char (char dumb, char *dumber)
#else
extern void meta9_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[9] = 1;
}

#ifdef __STDC__
extern void meta8_char (char dumb, char *dumber)
#else
extern void meta8_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[8] = 1;
}

#ifdef __STDC__
extern void meta7_char (char dumb, char *dumber)
#else
extern void meta7_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[7] = 1;
}

#ifdef __STDC__
extern void meta6_char (char dumb, char *dumber)
#else
extern void meta6_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[6] = 1;
}

#ifdef __STDC__
extern void meta5_char (char dumb, char *dumber)
#else
extern void meta5_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[5] = 1;
}

#ifdef __STDC__
extern void meta4_char (char dumb, char *dumber)
#else
extern void meta4_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[4] = 1 - current_screen->meta_hit[4];
}

#ifdef __STDC__
extern void meta3_char (char dumb, char *dumber)
#else
extern void meta3_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[3] = 1;
}

#ifdef __STDC__
extern void meta2_char (char dumb, char *dumber)
#else
extern void meta2_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[2] = 1;
}

#ifdef __STDC__
extern void meta1_char (char dumb, char *dumber)
#else
extern void meta1_char (dumb, dumber)
char dumb;
char *dumber;
#endif
{
	current_screen->meta_hit[1] = 1;
}

#ifdef __STDC__
extern void	quote_char (char c, char *dumber)
#else
extern void
quote_char(c, dumber)
	char	c;
	char	*dumber;
#endif
{
	current_screen->quote_hit = 1;
}

/* These four functions are boomerang functions, which allow the highlight
 * characters to be bound by simply having these functions put in the
 * appropriate characters when you press any key to which you have bound
 * that highlight character. >;-)
 */
#ifdef __STDC__
extern void insert_bold (char c, char *dumber)
#else
extern void insert_bold (c, dumber)
char c, *dumber;
#endif
{
	input_add_character (BOLD_TOG, dumber);
}

#ifdef __STDC__
extern void insert_reverse (char c, char *dumber)
#else
extern void insert_reverse (c, dumber)
char c, *dumber;
#endif
{
	input_add_character (REV_TOG, dumber);
}

#ifdef __STDC__
extern void insert_underline (char c, char *dumber)
#else
extern void insert_underline (c, dumber)
char c, *dumber;
#endif
{
	input_add_character (UND_TOG, dumber);
}

#ifdef __STDC__
extern void highlight_off (char c, char *dumber)
#else
extern void highlight_off (c, dumber)
char c, *dumber;
#endif
{
	input_add_character (ALL_OFF, dumber);
}

/* type_text: the BIND function TYPE_TEXT */
#ifdef __STDC__
extern void	type_text (char c, char *str)
#else
extern void
type_text(c, str)
	char	c,
		*str;
#endif
{
	/* Paranoia */
	if (!str)
		return;

	for (; *str; str++)
		input_add_character(*str, empty_string);
}

/*
 * clear_screen: the CLEAR_SCREEN function for BIND.  Clears the screen and
 * starts it if it is held 
 */
#ifdef __STDC__
extern void	clear_screen (char c, char *str)
#else
extern void
clear_screen(c, str)
	char	c,
		*str;
#endif
{
	hold_mode((Window *) 0, OFF, 1);
	e_clear(NULL, empty_string, empty_string);
}

/* parse_text: the bindable function that executes its string */
#ifdef __STDC__
extern void	parse_text (char c, char *str)
#else
extern void
parse_text(c, str)
	char	c,
		*str;
#endif
{
	parse_line(NULL, str, empty_string, 0, 0);
}


/*
 * edit_char: handles each character for an input stream.  Not too difficult
 * to work out.
 */
#ifdef __STDC__
extern void	edit_char (u_char key)
#else
extern void
edit_char(key)
	u_char	key;
#endif
{
	void	(*func) _((char, char *)) = NULL;
	char	*ptr = NULL;
	u_char	extended_key;
	WaitPrompt *oldprompt;
	int 	meta_hit = 0, 
		meta_not_hit;
	int 	i;
	u_char	dummy[2];

	/* were we waiting for a keypress? */
	if (current_screen->promptlist && current_screen->promptlist->type == WAIT_PROMPT_KEY)
	{
		dummy[0] = key, dummy[1] = 0;
		oldprompt = current_screen->promptlist;
		(*oldprompt->func)(oldprompt->data, dummy);
		set_input(empty_string);
		current_screen->promptlist = oldprompt->next;
		new_free(&oldprompt->data);
		new_free(&oldprompt->prompt);
		new_free((char **)&oldprompt);
		change_input_prompt(-1);
		return;
	}

	/* check to see if we are in a translation setting */
	if (translation)
		extended_key = transFromClient[key];
	else
		extended_key = key;


	/* Check to see if its an eight bit char and if we allow it */
	if (!get_int_var(EIGHT_BIT_CHARACTERS_VAR))
		key &= 0x7f;			/* mask out non-ascii crap */


	/* Check to see if this is a meta-key */
	for (i = 1; i <= 9; i++)
	{
		if (current_screen->meta_hit[i])
		{
			if (keys[i][key])
			{
				func = key_names[keys[i][key]->key_index].func;
				ptr = keys[i][key]->stuff;
			}
			current_screen->meta_hit[i] = 0;
			meta_hit = 1;
			break;
		}
	}
	if (!meta_hit)
	{
		if (keys[0][key])
		{
			func = key_names[keys[0][key]->key_index].func;
			ptr = keys[0][key]->stuff;
		}
	}

	/* is there a meta key that isnt still outstanding? */
	meta_not_hit = 1;
	for (i = 1; i <= 3; i++)
		meta_not_hit = meta_not_hit && !current_screen->meta_hit[i];
	for (i = 5; i <= 9; i++)
		meta_not_hit = meta_not_hit && !current_screen->meta_hit[i];

	if (meta_not_hit)
	{
		/* are we inside a menu? */
		if (current_screen->inside_menu == 1)
			menu_key(key);

		/* are we doing a digraph? */
		else if (current_screen->digraph_hit)
		{
			if (extended_key == 0x08 || extended_key == 0x7f)
				current_screen->digraph_hit = 0;
			else if (current_screen->digraph_hit == 1)
			{
				current_screen->digraph_first = extended_key;
				current_screen->digraph_hit = 2;
			}
			else if (current_screen->digraph_hit == 2)
			{
				if ((extended_key = get_digraph(extended_key)) != '\0')
					input_add_character(extended_key, empty_string);
				else
					term_beep();
			}
		}

		/* did we just hit the quote character? */
		else if (current_screen->quote_hit)
		{
			current_screen->quote_hit = 0;
			input_add_character(extended_key, empty_string);
		}

		/* nope. none of these.  just a regular character */
		else if (func)
			func(extended_key, ptr ? ptr : empty_string);
	}
	else
		term_beep();	/* two metas in a row gets a beep */
}

