[BACK]Return to ee.c CVS log [TXT][DIR] Up to [contributed] / dgamelaunch-openbsd

File: [contributed] / dgamelaunch-openbsd / ee.c (download)

Revision 1.1, Tue Mar 9 14:36:00 2021 UTC (3 years, 1 month ago) by rubenllorente
Branch point for: MAIN

Initial revision

/*
 |	ee (easy editor)
 |
 |	An easy to use, simple screen oriented editor.
 |
 |	written by Hugh Mahon
 |
 |	THIS MATERIAL IS PROVIDED "AS IS".  THERE ARE
 |	NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
 |	MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
 |	IMPLIED WARRANTIES OF MERCHANTABILITY AND
 |	FITNESS FOR A PARTICULAR PURPOSE.  Neither
 |	Hewlett-Packard nor Hugh Mahon shall be liable
 |	for errors contained herein, nor for
 |	incidental or consequential damages in
 |	connection with the furnishing, performance or
 |	use of this material.  Neither Hewlett-Packard
 |	nor Hugh Mahon assumes any responsibility for
 |	the use or reliability of this software or
 |	documentation.  This software and
 |	documentation is totally UNSUPPORTED.  There
 |	is no support contract available.  Hewlett-
 |	Packard has done NO Quality Assurance on ANY
 |	of the program or documentation.  You may find
 |	the quality of the materials inferior to
 |	supported materials.
 |
 |	This software is not a product of Hewlett-Packard, Co., or any 
 |	other company.  No support is implied or offered with this software.
 |	You've got the source, and you're on your own.
 |
 |	This software may be distributed under the terms of Larry Wall's 
 |	Artistic license, a copy of which is included in this distribution. 
 |
 |	This notice must be included with this software and any derivatives.
 |
 |	This editor was purposely developed to be simple, both in 
 |	interface and implementation.  This editor was developed to 
 |	address a specific audience: the user who is new to computers 
 |	(especially UNIX).
 |	
 |	ee is not aimed at technical users; for that reason more 
 |	complex features were intentionally left out.  In addition, 
 |	ee is intended to be compiled by people with little computer 
 |	experience, which means that it needs to be small, relatively 
 |	simple in implementation, and portable.
 |
 |	This software and documentation contains
 |	proprietary information which is protected by
 |	copyright.  All rights are reserved.
 |
 |	$Header: /var/cvs/dgamelaunch/ee.c,v 1.10 2004/01/26 16:54:02 joshk Exp $
 |
 */

#include <wchar.h>
wchar_t *ee_copyright_message = 
L"Copyright (c) 1986, 1990, 1991, 1992, 1993, 1994, 1995, 1996 Hugh Mahon ";

wchar_t *ee_long_notice[] = {
	L"This software and documentation contains", 
	L"proprietary information which is protected by", 
	L"copyright.  All rights are reserved."
	};

wchar_t *version = L"@(#) ee, version 1.4.1  $Revision: 1.10 $";

#include <locale.h>
#include <curses.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <pwd.h>

#include <sys/wait.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <ctype.h>

#ifndef SIGCHLD
#define SIGCHLD SIGCLD
#endif

#define MAX_FILE 1048576

#define TAB 9
#define max(a, b)	(a > b ? a : b)
#define min(a, b)	(a < b ? a : b)

/*
 |	defines for type of data to show in info window
 */

#define CONTROL_KEYS 1
#define COMMANDS     2

struct text {
	wchar_t *line;		/* line of characters		*/
	int line_number;	/* line number			*/
	int line_length;	/* actual number of characters in the line */
	int max_length;	/* maximum number of characters the line handles */
	struct text *next_line;		/* next line of text		*/
	struct text *prev_line;		/* previous line of text	*/
	};

struct text *first_line;	/* first line of current buffer		*/
struct text *dlt_line;		/* structure for info on deleted line	*/
struct text *curr_line;		/* current line cursor is on		*/
struct text *tmp_line;		/* temporary line pointer		*/
struct text *srch_line;		/* temporary pointer for search routine */

int d_wrd_len;			/* length of deleted word		*/
int position;			/* offset in bytes from begin of line	*/
int scr_pos;			/* horizontal position			*/
int scr_vert;			/* vertical position on screen		*/
int scr_horz;			/* horizontal position on screen	*/
int tmp_vert, tmp_horz;
int input_file;			/* indicate to read input file		*/
int recv_file;			/* indicate reading a file		*/
int edit;			/* continue executing while true	*/
int gold;			/* 'gold' function key pressed		*/
int fildes;			/* file descriptor			*/
int case_sen;			/* case sensitive search flag		*/
int last_line;			/* last line for text display		*/
int last_col;			/* last column for text display		*/
int horiz_offset = 0;		/* offset from left edge of text	*/
int clear_com_win;		/* flag to indicate com_win needs clearing */
int text_changes = FALSE;	/* indicate changes have been made to text */
int get_fd;			/* file descriptor for reading a file	*/
int info_window = TRUE;		/* flag to indicate if help window visible */
int info_type = CONTROL_KEYS;	/* flag to indicate type of info to display */
int expand_tabs = TRUE;		/* flag for expanding tabs		*/
int right_margin = 0;		/* the right margin 			*/
int observ_margins = TRUE;	/* flag for whether margins are observed */
int out_pipe;			/* flag that info is piped out		*/
int in_pipe;			/* flag that info is piped in		*/
int formatted = FALSE;		/* flag indicating paragraph formatted	*/
int nohighlight = FALSE;	/* turns off highlighting		*/
int eightbit = TRUE;		/* eight bit character flag		*/
int local_LINES = 0;		/* copy of LINES, to detect when win resizes */
int local_COLS = 0;		/* copy of COLS, to detect when win resizes  */
int curses_initialized = FALSE;	/* flag indicating if curses has been started*/
int emacs_keys_mode = TRUE;	/* mode for if emacs key binings are used    */

wchar_t *point;		/* points to current position in line	*/
wchar_t *srch_str;	/* pointer for search string		*/
wchar_t *u_srch_str;	/* pointer to non-case sensitive search	*/
wchar_t *srch_1;		/* pointer to start of suspect string	*/
wchar_t *srch_2;		/* pointer to next character of string	*/
wchar_t *srch_3;
char *in_file_name = NULL;	/* name of input file		*/
char *tmp_file;	/* temporary file name			*/
wchar_t *d_char;		/* deleted character			*/
wchar_t *d_word;		/* deleted word				*/
wchar_t *d_line;		/* deleted line				*/
wchar_t *start_at_line = NULL;	/* move to this line at start of session*/
int in;				/* input character			*/

FILE *temp_fp;			/* temporary file pointer		*/

wchar_t *table[] = { 
	L"^@", L"^A", L"^B", L"^C", L"^D", L"^E", L"^F", L"^G", L"^H", L"\t", L"^J", 
	L"^K", L"^L", L"^M", L"^N", L"^O", L"^P", L"^Q", L"^R", L"^S", L"^T", L"^U", 
	L"^V", L"^W", L"^X", L"^Y", L"^Z", L"^[", L"^\\", L"^]", L"^^", L"^_"
	};

WINDOW *com_win;
WINDOW *text_win;
WINDOW *help_win;
WINDOW *info_win;

#if defined(__STDC__) || defined(__cplusplus)
#define P_(s) s
#else
#define P_(s) ()
#endif


/*
 |	The following structure allows menu items to be flexibly declared.
 |	The first item is the string describing the selection, the second 
 |	is the address of the procedure to call when the item is selected,
 |	and the third is the argument for the procedure.
 |
 |	For those systems with i18n, the string should be accompanied by a
 |	catalog number.  The 'int *' should be replaced with 'void *' on 
 |	systems with that type.
 |
 |	The first menu item will be the title of the menu, with NULL 
 |	parameters for the procedure and argument, followed by the menu items.
 |
 |	If the procedure value is NULL, the menu item is displayed, but no 
 |	procedure is called when the item is selected.  The number of the 
 |	item will be returned.  If the third (argument) parameter is -1, no 
 |	argument is given to the procedure when it is called.
 */

struct menu_entries
{
	wchar_t *item_string;
	int (*procedure)P_((struct menu_entries *));
	struct menu_entries *ptr_argument;
	int (*iprocedure)P_((int));
	void (*nprocedure)P_((void));
	int argument;
};

int main(int argc, char *argv[]);
wchar_t *resiz_line(int factor, struct text *rline, int rpos);
void insert(int character);
void delete(int disp);
void scanline(wchar_t *pos);
int tabshift(int temp_int);
int out_char(WINDOW *window, int character, int column);
int len_char(wchar_t character, int column);
void draw_line(int vertical, int horiz, wchar_t *ptr, int t_pos, int length);
void insert_line(int disp);
struct text *txtalloc(void);
wchar_t *next_word(wchar_t *string);
void prev_word(void);
void control(void);
void emacs_control(void);
void bottom(void);
void top(void);
void nextline(void);
void prevline(void);
void left(int disp);
void right(int disp);
void find_pos(void);
void up(void);
void down(void);
void function_key(void);
void command_prompt(void);
void command(wchar_t *cmd_str1);
int scan(wchar_t *line, int offset, int column);
wchar_t *get_string(wchar_t *prompt, int advance);
int compare(wchar_t *string1, wchar_t *string2, int sensitive);
void goto_line(wchar_t *cmd_str);
void midscreen(int line, wchar_t *pnt);
void check_fp(void);
void get_file(char *file_name);
void get_line(int length, char *in_string, int *append);
void draw_screen(void);
void ee_finish(void);
int quit(int noverify);
void edit_abort(int arg);
void delete_text(void);
int write_file(char *file_name, int fd);
int search(int display_message);
void search_prompt(void);
void del_char(void);
void undel_char(void);
void del_word(void);
void undel_word(void);
void del_line(void);
void undel_line(void);
void adv_word(void);
void move_rel(char direction, int lines);
void eol(void);
void bol(void);
void adv_line(void);
void set_up_term(void);
void resize_check(void);
int menu_op(struct menu_entries menu_list[]);
void paint_menu(struct menu_entries menu_list[], int max_width, int max_height, int list_size, int top_offset, WINDOW *menu_win, int off_start, int vert_size);
void help(void);
void paint_info_win(void);
void no_info_window(void);
void create_info_window(void);
int file_op(int arg);
void leave_op(void);
void redraw(void);
int Blank_Line(struct text *test_line);
void echo_string(wchar_t *string);
int first_word_len(struct text *test_line);
wchar_t *is_in_string(wchar_t *string, wchar_t *substring);
int unique_test(wchar_t *string, wchar_t *list[]);
void strings_init(void);

#undef P_
/*
 |	allocate space here for the strings that will be in the menu
 */

struct menu_entries leave_menu[] = {
	{L"", NULL, NULL, NULL, NULL, -1}, 
	{L"", NULL, NULL, NULL, ee_finish, -1}, 
	{L"", NULL, NULL, quit, NULL, TRUE}, 
	{NULL, NULL, NULL, NULL, NULL, -1}
	};

#define READ_FILE 1
#define WRITE_FILE 2
#define SAVE_FILE 3

struct menu_entries search_menu[] = {
	{L"", NULL, NULL, NULL, NULL, 0}, 
	{L"", NULL, NULL, NULL, search_prompt, -1},
	{L"", NULL, NULL, search, NULL, TRUE},
	{NULL, NULL, NULL, NULL, NULL, -1}
	};

struct menu_entries main_menu[] = {
	{L"", NULL, NULL, NULL, NULL, -1}, 
	{L"", NULL, NULL, NULL, leave_op, -1}, 
	{L"", NULL, NULL, NULL, help, -1},
	{L"", NULL, NULL, file_op, NULL, SAVE_FILE},
	{L"", NULL, NULL, NULL, redraw, -1}, 
	{L"", menu_op, search_menu, NULL, NULL, -1}, 
	{NULL, NULL, NULL, NULL, NULL, -1}
	};

wchar_t *help_text[23];
wchar_t *control_keys[5];

wchar_t *emacs_help_text[22];
wchar_t *emacs_control_keys[5];

wchar_t *command_strings[5];
wchar_t *commands[32];

#define MENU_WARN 1

#define max_alpha_char 36

/*
 |	Declarations for strings for localization
 */

wchar_t *com_win_message;		/* to be shown in com_win if no info window */
char *no_file_string;
wchar_t *ascii_code_str;
wchar_t *command_str;
char *char_str;
char *unkn_cmd_str;
wchar_t *non_unique_cmd_msg;
char *line_num_str;
char *line_len_str;
char *current_file_str;
wchar_t *usage0;
wchar_t *usage1;
wchar_t *usage2;
wchar_t *usage3;
wchar_t *usage4;
char *file_is_dir_msg;
char *new_file_msg;
char *cant_open_msg;
wchar_t *open_file_msg;
char *file_read_fin_msg;
char *reading_file_msg;
char *read_only_msg;
char *file_read_lines_msg;
wchar_t *save_file_name_prompt;
char *file_not_saved_msg;
wchar_t *changes_made_prompt;
wchar_t *yes_char;
wchar_t *file_exists_prompt;
char *create_file_fail_msg;
char *writing_file_msg;
char *file_written_msg;
char *searching_msg;
char *str_not_found_msg;
wchar_t *search_prompt_str;
wchar_t *continue_msg;
wchar_t *menu_cancel_msg;
wchar_t *menu_size_err_msg;
wchar_t *press_any_key_msg;
wchar_t *ON;
wchar_t *OFF;
wchar_t *HELP;
wchar_t *SAVE;
wchar_t *READ;
wchar_t *LINE;
wchar_t *FILE_str;
wchar_t *CHARACTER;
wchar_t *REDRAW;
wchar_t *RESEQUENCE;
wchar_t *AUTHOR;
wchar_t *ee_VERSION;
wchar_t *CASE;
wchar_t *NOCASE;
wchar_t *EXPAND;
wchar_t *NOEXPAND;
wchar_t *Exit_string;
wchar_t *QUIT_string;
wchar_t *INFO;
wchar_t *NOINFO;
wchar_t *MARGINS;
wchar_t *NOMARGINS;
wchar_t *AUTOFORMAT;
wchar_t *NOAUTOFORMAT;
wchar_t *Echo;
wchar_t *PRINTCOMMAND;
wchar_t *RIGHTMARGIN;
wchar_t *HIGHLIGHT;
wchar_t *NOHIGHLIGHT;
wchar_t *EIGHTBIT;
wchar_t *NOEIGHTBIT;
wchar_t *EMACS_string;
wchar_t *NOEMACS_string;
wchar_t *cancel_string;
char *menu_too_lrg_msg;
wchar_t *more_above_str, *more_below_str;

#ifndef __STDC__
#ifndef HAS_STDLIB
extern char *malloc();
extern char *realloc();
extern char *getenv();
FILE *fopen();			/* declaration for open function	*/
#endif /* HAS_STDLIB */
#endif /* __STDC__ */

int
main(argc, argv)		/* beginning of main program		*/
int argc;
char *argv[];
{
	int counter;

	setlocale(LC_ALL, "");
	for (counter = 1; counter < 24; counter++)
	{
	  if (!(counter == SIGKILL || counter == SIGSTOP))
		signal(counter, SIG_IGN);
	}

	signal(SIGCHLD, SIG_DFL);
	signal(SIGSEGV, SIG_DFL);
	signal(SIGINT, edit_abort);
	d_char = malloc(3 * sizeof(wchar_t));	/* provide a buffer for multi-byte chars */
	d_word = malloc(150 * sizeof(wchar_t));
	*d_word = '\0';
	d_line = NULL;
	dlt_line = txtalloc();
	dlt_line->line = d_line;
	dlt_line->line_length = 0;
	curr_line = first_line = txtalloc();
	curr_line->line = point = malloc(10 * sizeof(wchar_t));
	curr_line->line_length = 1;
	curr_line->max_length = 10;
	curr_line->prev_line = NULL;
	curr_line->next_line = NULL;
	curr_line->line_number  = 1;
	srch_str = NULL;
	u_srch_str = NULL;
	position = 1;
	scr_pos =0;
	scr_vert = 0;
	scr_horz = 0;
	edit = TRUE;
	gold = case_sen = FALSE;
	strings_init();

	if (argc != 2)
	{
	  puts("need a filename! bailing out.");
	  return 1;
	}
	else
	{
	  tmp_file = strdup(argv[1]);
	  input_file = recv_file = TRUE;
	}
	
	set_up_term();
	if (right_margin == 0)
		right_margin = COLS - 1;
	
	if (!tmp_file)
	{
		wprintw(com_win, no_file_string);
		wrefresh(com_win);
	}
	else
		check_fp();

	clear_com_win = TRUE;

	while(edit) 
	{
		int keyt;
		wrefresh(text_win);
		keyt = wget_wch(text_win, &in);
		if (keyt == ERR)
			exit(0);

		resize_check();

		if (clear_com_win)
		{
			clear_com_win = FALSE;
			wmove(com_win, 0, 0);
			werase(com_win);
			if (!info_window)
			{
				wprintw(com_win, "%S", com_win_message);
			}
			wrefresh(com_win);
		}

		if (keyt == KEY_CODE_YES)
			function_key();
		else if ((in == '\10') || (in == 127))
		{
			in = 8;		/* make sure key is set to backspace */
			delete(TRUE);
		}
		else if ((in > 31) || (in == 9))
			insert(in);
		else if ((in >= 0) && (in <= 31))
		{
			if (emacs_keys_mode)
				emacs_control();
			else
				control();
		}
	}
	return(0);
}

wchar_t *
resiz_line(factor, rline, rpos)	/* resize the line to length + factor*/
int factor;		/* resize factor				*/
struct text *rline;	/* position in line				*/
int rpos;
{
	wchar_t *rpoint;
	int resiz_var;
 
	rline->max_length += factor;
	rpoint = rline->line = realloc(rline->line, rline->max_length * sizeof(wchar_t));
	for (resiz_var = 1 ; (resiz_var < rpos) ; resiz_var++)
		rpoint++;
	return(rpoint);
}

void 
insert(character)		/* insert character into line		*/
int character;			/* new character			*/
{
	int counter;
	int value;
	wchar_t *temp;	/* temporary pointer			*/
	wchar_t *temp2;	/* temporary pointer			*/

	if ((character == '\011') && (expand_tabs))
	{
		counter = len_char('\011', scr_horz);
		for (; counter > 0; counter--)
			insert(' ');
		return;
	}
	text_changes = TRUE;
	if ((curr_line->max_length - curr_line->line_length) < 5)
		point = resiz_line(10, curr_line, position);
	curr_line->line_length++;
	temp = point;
	counter = position;
	while (counter < curr_line->line_length)	/* find end of line */
	{
		counter++;
		temp++;
	}
	temp++;			/* increase length of line by one	*/
	while (point < temp)
	{
		temp2=temp - 1;
		*temp= *temp2;	/* shift characters over by one		*/
		temp--;
	}
	*point = character;	/* insert new character			*/
	wclrtoeol(text_win);
	if ((character >= 0) && (character < ' ')) /* check for TAB character*/
	{
		scr_pos = scr_horz += out_char(text_win, character, scr_horz);
		point++;
		position++;
	}
	else
	{
		waddnwstr(text_win, &character, 1);
		scr_pos = ++scr_horz;
		point++;
		position ++;
	}

	if ((observ_margins) && (right_margin < scr_pos))
	{
		counter = position;
		while (scr_pos > right_margin)
			prev_word();
		if (scr_pos == 0)
		{
			while (position < counter)
				right(TRUE);
		}
		else
		{
			counter -= position;
			insert_line(TRUE);
			for (value = 0; value < counter; value++)
				right(TRUE);
		}
	}

	if ((scr_horz - horiz_offset) > last_col)
	{
		horiz_offset += 8;
		midscreen(scr_vert, point);
	}

	else if ((character != ' ') && (character != '\t'))
		formatted = FALSE;

	draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
}

void 
delete(disp)			/* delete character		*/
int disp;
{
	wchar_t *tp;
	wchar_t *temp2;
	struct text *temp_buff;
	int temp_vert;
	int temp_pos;
	int del_width = 1;

	if (point != curr_line->line)	/* if not at beginning of line	*/
	{
		text_changes = TRUE;
		temp2 = tp = point;
		tp -= del_width;
		point -= del_width;
		position -= del_width;
		temp_pos = position;
		curr_line->line_length -= del_width;
		if ((*tp < ' ') || (*tp >= 127))	/* check for TAB */
			scanline(tp);
		else
			scr_horz -= del_width;
		scr_pos = scr_horz;
		if (in == 8)
		{
			if (del_width == 1)
				*d_char = *point; /* save deleted character  */
			else
			{
				d_char[0] = *point;
				d_char[1] = *(point + 1);
			}
			d_char[del_width] = '\0';
		}
		while (temp_pos <= curr_line->line_length)
		{
			temp_pos++;
			*tp = *temp2;
			tp++;
			temp2++;
		}
		if (scr_horz < horiz_offset)
		{
			horiz_offset -= 8;
			midscreen(scr_vert, point);
		}
	}
	else if (curr_line->prev_line != NULL)
	{
		text_changes = TRUE;
		left(disp);			/* go to previous line	*/
		temp_buff = curr_line->next_line;
		point = resiz_line(temp_buff->line_length, curr_line, position);
		if (temp_buff->next_line != NULL)
			temp_buff->next_line->prev_line = curr_line;
		curr_line->next_line = temp_buff->next_line;
		temp2 = temp_buff->line;
		if (in == 8)
		{
			d_char[0] = '\n';
			d_char[1] = '\0';
		}
		tp = point;
		temp_pos = 1;
		while (temp_pos < temp_buff->line_length)
		{
			curr_line->line_length++;
			temp_pos++;
			*tp = *temp2;
			tp++;
			temp2++;
		}
		*tp = '\0';
		free(temp_buff->line);
		free(temp_buff);
		temp_buff = curr_line;
		temp_vert = scr_vert;
		scr_pos = scr_horz;
		if (scr_vert < last_line)
		{
			wmove(text_win, scr_vert + 1, 0);
			wdeleteln(text_win);
		}
		while ((temp_buff != NULL) && (temp_vert < last_line))
		{
			temp_buff = temp_buff->next_line;
			temp_vert++;
		}
		if ((temp_vert == last_line) && (temp_buff != NULL))
		{
			tp = temp_buff->line;
			wmove(text_win, last_line,0);
			wclrtobot(text_win);
			draw_line(last_line, 0, tp, 1, temp_buff->line_length);
			wmove(text_win, scr_vert, (scr_horz - horiz_offset));
		}
	}
	draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
	formatted = FALSE;
}

void 
scanline(pos)	/* find the proper horizontal position for the pointer	*/
wchar_t *pos;
{
	int temp;
	wchar_t *ptr;

	ptr = curr_line->line;
	temp = 0;
	while (ptr < pos)
	{
		if (*ptr <= 8)
			temp += 2;
		else if (*ptr == 9)
			temp += tabshift(temp);
		else if ((*ptr >= 10) && (*ptr <= 31))
			temp += 2;
		else if ((*ptr >= 32) && (*ptr < 127))
			temp++;
		else if (*ptr == 127)
			temp += 2;
		else if (!eightbit)
			temp += 5;
		else
			temp++;
		ptr++;
	}
	scr_horz = temp;
	if ((scr_horz - horiz_offset) > last_col)
	{
		horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
		midscreen(scr_vert, point);
	}
	else if (scr_horz < horiz_offset)
	{
		horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
		midscreen(scr_vert, point);
	}
}

int 
tabshift(temp_int)		/* give the number of spaces to shift	*/
int temp_int;
{
	int leftover;

	leftover = ((temp_int + 1) % 8);
	if (leftover == 0)
		return (1);
	else
		return (9 - leftover);
}

int 
out_char(window, character, column)	/* output non-printing character */
WINDOW *window;
int character;
int column;
{
	int i1, i2;
	wchar_t *string;

	if (character == TAB)
	{
		i1 = tabshift(column);
		for (i2 = 0; 
		  (i2 < i1) && (((column+i2+1)-horiz_offset) < last_col); i2++)
		{
			waddch(window, ' ');
		}
		return(i1);
	}
	else if ((character >= '\0') && (character < ' '))
	{
		string = table[(int) character];
	}
	else
	{
		waddnwstr(window, &character, 1);
		return(1);
	}
	for (i2 = 0; (string[i2] != '\0') && (((column+i2+1)-horiz_offset) < last_col); i2++)
		waddch(window, string[i2]);
	return(wcslen(string));
}

int 
len_char(character, column)	/* return the length of the character	*/
wchar_t character;
int column;	/* the column must be known to provide spacing for tabs	*/
{
	int length;

	if (character == '\t')
		length = tabshift(column);
	else if ((character >= 0) && (character < 32))
		length = 2;
	else if ((character >= 32) && (character <= 126))
		length = 1;
	else if (character == 127)
		length = 2;
	else if (((character > 126) || (character < 0)) && (!eightbit))
		length = 5;
	else
		length = 1;

	return(length);
}

void 
draw_line(vertical, horiz, ptr, t_pos, length)	/* redraw line from current position */
int vertical;	/* current vertical position on screen		*/
int horiz;	/* current horizontal position on screen	*/
wchar_t *ptr;	/* pointer to line				*/
int t_pos;	/* current position (offset in bytes) from bol	*/
int length;	/* length (in bytes) of line			*/
{
	int d;		/* partial length of special or tab char to display  */
	wchar_t *temp;	/* temporary pointer to position in line	     */
	int abs_column;	/* offset in screen units from begin of line	     */
	int column;	/* horizontal position on screen		     */
	int row;	/* vertical position on screen			     */
	int posit;	/* temporary position indicator within line	     */

	abs_column = horiz;
	column = horiz - horiz_offset;
	row = vertical;
	temp = ptr;
	d = 0;
	posit = t_pos;
	if (column < 0)
	{
		wmove(text_win, row, 0);
		wclrtoeol(text_win);
	}
	while (column < 0)
	{
		d = len_char(*temp, abs_column);
		abs_column += d;
		column += d;
		posit++;
		temp++;
	}
	wmove(text_win, row, column);
	wclrtoeol(text_win);
	while ((posit < length) && (column <= last_col))
	{
		if (*temp < 32)
		{
			column += len_char(*temp, abs_column);
			abs_column += out_char(text_win, *temp, abs_column);
		}
		else
		{
			abs_column++;
			column++;
			waddnwstr(text_win, temp, 1);
		}
		posit++;
		temp++;
	}
	if (column < last_col)
		wclrtoeol(text_win);
	wmove(text_win, vertical, (horiz - horiz_offset));
}

void 
insert_line(disp)			/* insert new line		*/
int disp;
{
	int temp_pos;
	int temp_pos2;
	wchar_t *temp;
	wchar_t *extra;
	struct text *temp_nod;

	text_changes = TRUE;
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
	wclrtoeol(text_win);
	temp_nod= txtalloc();
	temp_nod->line = extra= malloc(10 * sizeof(wchar_t));
	temp_nod->line_length = 1;
	temp_nod->max_length = 10;
	temp_nod->line_number = curr_line->line_number + 1;
	temp_nod->next_line = curr_line->next_line;
	if (temp_nod->next_line != NULL)
		temp_nod->next_line->prev_line = temp_nod;
	temp_nod->prev_line = curr_line;
	curr_line->next_line = temp_nod;
	temp_pos2 = position;
	temp = point;
	if (temp_pos2 < curr_line->line_length)
	{
		temp_pos = 1;
		while (temp_pos2 < curr_line->line_length)
		{
			if ((temp_nod->max_length - temp_nod->line_length)< 5)
				extra = resiz_line(10, temp_nod, temp_pos);
			temp_nod->line_length++;
			temp_pos++;
			temp_pos2++;
			*extra= *temp;
			extra++;
			temp++;
		}
		temp=point;
		*temp = '\0';
		temp = resiz_line((1 - temp_nod->line_length), curr_line, position);
		curr_line->line_length = 1 + temp - curr_line->line;
	}
	curr_line->line_length = position;
	curr_line = temp_nod;
	*extra = '\0';
	position = 1;
	point= curr_line->line;
	if (disp)
	{
		if (scr_vert < last_line)
		{
			scr_vert++;
			wclrtoeol(text_win);
			wmove(text_win, scr_vert, 0);
			winsertln(text_win);
		}
		else
		{
			wmove(text_win, 0,0);
			wdeleteln(text_win);
			wmove(text_win, last_line,0);
			wclrtobot(text_win);
		}
		scr_pos = scr_horz = 0;
		if (horiz_offset)
		{
			horiz_offset = 0;
			midscreen(scr_vert, point);
		}
		draw_line(scr_vert, scr_horz, point, position,
			curr_line->line_length);
	}
}

struct text *txtalloc()		/* allocate space for line structure	*/
{
	return((struct text *) malloc(sizeof( struct text)));
}

wchar_t *next_word(string)		/* move to next word in string		*/
wchar_t *string;
{
	while ((*string != '\0') && ((*string != 32) && (*string != 9)))
		string++;
	while ((*string != '\0') && ((*string == 32) || (*string == 9)))
		string++;
	return(string);
}

int watoi(wchar_t *s)
{
	int x = 0;
	while (*s >= '0' && *s <= '9')
		x = x * 10 + *s++ - '0';
	return x;
}

void 
prev_word()	/* move to start of previous word in text	*/
{
	if (position != 1)
	{
		if ((position != 1) && ((point[-1] == ' ') || (point[-1] == '\t')))
		{	/* if at the start of a word	*/
			while ((position != 1) && ((*point != ' ') && (*point != '\t')))
				left(TRUE);
		}
		while ((position != 1) && ((*point == ' ') || (*point == '\t')))
			left(TRUE);
		while ((position != 1) && ((*point != ' ') && (*point != '\t')))
			left(TRUE);
		if ((position != 1) && ((*point == ' ') || (*point == '\t')))
			right(TRUE);
	}
	else
		left(TRUE);
}

void 
control()			/* use control for commands		*/
{
	wchar_t *string;

	if (in == 1)		/* control a	*/
	{
		string = get_string(ascii_code_str, TRUE);
		if (*string != '\0')
		{
			in = watoi(string);
			wmove(text_win, scr_vert, (scr_horz - horiz_offset));
			insert(in);
		}
		free(string);
	}
	else if (in == 2)	/* control b	*/
		bottom();
	else if (in == 3)	/* control c	*/
	{
		command_prompt();
	}
	else if (in == 4)	/* control d	*/
		down();
	else if (in == 5)	/* control e	*/
		search_prompt();
	else if (in == 6)	/* control f	*/
		undel_char();
	else if (in == 7)	/* control g	*/
		bol();
	else if (in == 8)	/* control h	*/
		delete(TRUE);
	else if (in == 9)	/* control i	*/
		;
	else if (in == 10)	/* control j	*/
		insert_line(TRUE);
	else if (in == 11)	/* control k	*/
		del_char();
	else if (in == 12)	/* control l	*/
		left(TRUE);
	else if (in == 13)	/* control m	*/
		insert_line(TRUE);
	else if (in == 14)	/* control n	*/
		move_rel('d', max(5, (last_line - 5)));
	else if (in == 15)	/* control o	*/
		eol();
	else if (in == 16)	/* control p	*/
		move_rel('u', max(5, (last_line - 5)));
	else if (in == 17)	/* control q	*/
		;
	else if (in == 18)	/* control r	*/
		right(TRUE);
	else if (in == 19)	/* control s	*/
		;
	else if (in == 20)	/* control t	*/
		top();
	else if (in == 21)	/* control u	*/
		up();
	else if (in == 22)	/* control v	*/
		undel_word();
	else if (in == 23)	/* control w	*/
		del_word();
	else if (in == 24)	/* control x	*/
		search(TRUE);
	else if (in == 25)	/* control y	*/
		del_line();
	else if (in == 26)	/* control z	*/
		undel_line();
	else if (in == 27)	/* control [ (escape)	*/
	{
		menu_op(main_menu);
	}	
}

/*
 |	Emacs control-key bindings
 */

void 
emacs_control()
{
	wchar_t *string;

	if (in == 1)		/* control a	*/
		bol();
	else if (in == 2)	/* control b	*/
		left(TRUE);
	else if (in == 3)	/* control c	*/
	{
		command_prompt();
	}
	else if (in == 4)	/* control d	*/
		del_char();
	else if (in == 5)	/* control e	*/
		eol();
	else if (in == 6)	/* control f	*/
		right(TRUE);
	else if (in == 7)	/* control g	*/
		move_rel('u', max(5, (last_line - 5)));
	else if (in == 8)	/* control h	*/
		delete(TRUE);
	else if (in == 9)	/* control i	*/
		;
	else if (in == 10)	/* control j	*/
		undel_char();
	else if (in == 11)	/* control k	*/
		del_line();
	else if (in == 12)	/* control l	*/
		undel_line();
	else if (in == 13)	/* control m	*/
		insert_line(TRUE);
	else if (in == 14)	/* control n	*/
		down();
	else if (in == 15)	/* control o	*/
	{
		string = get_string(ascii_code_str, TRUE);
		if (*string != '\0')
		{
			in = watoi(string);
			wmove(text_win, scr_vert, (scr_horz - horiz_offset));
			insert(in);
		}
		free(string);
	}
	else if (in == 16)	/* control p	*/
		up();
	else if (in == 17)	/* control q	*/
		;
	else if (in == 18)	/* control r	*/
		undel_word();
	else if (in == 19)	/* control s	*/
		;
	else if (in == 20)	/* control t	*/
		top();
	else if (in == 21)	/* control u	*/
		bottom();
	else if (in == 22)	/* control v	*/
		move_rel('d', max(5, (last_line - 5)));
	else if (in == 23)	/* control w	*/
		del_word();
	else if (in == 24)	/* control x	*/
		search(TRUE);
	else if (in == 25)	/* control y	*/
		search_prompt();
	else if (in == 26)	/* control z	*/
		adv_word();
	else if (in == 27)	/* control [ (escape)	*/
	{
		menu_op(main_menu);
	}	
}

void 
bottom()			/* go to bottom of file			*/
{
	while (curr_line->next_line != NULL)
		curr_line = curr_line->next_line;
	point = curr_line->line;
	if (horiz_offset)
		horiz_offset = 0;
	position = 1;
	midscreen(last_line, point);
	scr_pos = scr_horz;
}

void 
top()				/* go to top of file			*/
{
	while (curr_line->prev_line != NULL)
		curr_line = curr_line->prev_line;
	point = curr_line->line;
	if (horiz_offset)
		horiz_offset = 0;
	position = 1;
	midscreen(0, point);
	scr_pos = scr_horz;
}

void 
nextline()			/* move pointers to start of next line	*/
{
	curr_line = curr_line->next_line;
	point = curr_line->line;
	position = 1;
	if (scr_vert == last_line)
	{
		wmove(text_win, 0,0);
		wdeleteln(text_win);
		wmove(text_win, last_line,0);
		wclrtobot(text_win);
		draw_line(last_line,0,point,1,curr_line->line_length);
	}
	else
		scr_vert++;
}

void 
prevline()			/* move pointers to start of previous line*/
{
	curr_line = curr_line->prev_line;
	point = curr_line->line;
	position = 1;
	if (scr_vert == 0)
	{
		winsertln(text_win);
		draw_line(0,0,point,1,curr_line->line_length);
	}
	else
		scr_vert--;
	while (position < curr_line->line_length)
	{
		position++;
		point++;
	}
}

void 
left(disp)				/* move left one character	*/
int disp;
{
	if (point != curr_line->line)	/* if not at begin of line	*/
	{
		point--;
		position--;
		scanline(point);
		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
		scr_pos = scr_horz;
	}
	else if (curr_line->prev_line != NULL)
	{
		if (!disp)
		{
			curr_line = curr_line->prev_line;
			point = curr_line->line + curr_line->line_length;
			position = curr_line->line_length;
			return;
		}
		position = 1;
		prevline();
		scanline(point);
		scr_pos = scr_horz;
		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
	}
}

void 
right(disp)				/* move right one character	*/
int disp;
{
	if (position < curr_line->line_length)
	{
		point++;
		position++;
		scanline(point);
		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
		scr_pos = scr_horz;
	}
	else if (curr_line->next_line != NULL)
	{
		if (!disp)
		{
			curr_line = curr_line->next_line;
			point = curr_line->line;
			position = 1;
			return;
		}
		nextline();
		scr_pos = scr_horz = 0;
		if (horiz_offset)
		{
			horiz_offset = 0;
			midscreen(scr_vert, point);
		}
		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
		position = 1;	
	}
}

void 
find_pos()		/* move to the same column as on other line	*/
{
	scr_horz = 0;
	position = 1;
	while ((scr_horz < scr_pos) && (position < curr_line->line_length))
	{
		if (*point == 9)
			scr_horz += tabshift(scr_horz);
		else if (*point < ' ')
			scr_horz += 2;
		else if ((*point > 127) && ((curr_line->line_length - position) >= 2))
		{
			scr_horz += 2;
			point++;
			position++;
		}
		else
			scr_horz++;
		position++;
		point++;
	}
	if ((scr_horz - horiz_offset) > last_col)
	{
		horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
		midscreen(scr_vert, point);
	}
	else if (scr_horz < horiz_offset)
	{
		horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
		midscreen(scr_vert, point);
	}
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
}

void 
up()					/* move up one line		*/
{
	if (curr_line->prev_line != NULL)
	{
		prevline();
		point = curr_line->line;
		find_pos();
	}
}

void 
down()					/* move down one line		*/
{
	if (curr_line->next_line != NULL)
	{
		nextline();
		find_pos();
	}
}

void 
function_key()				/* process function key		*/
{
	if (in == KEY_LEFT)
		left(TRUE);
	else if (in == KEY_RIGHT)
		right(TRUE);
	else if ( in == KEY_HOME)
		top();
	else if ( in == KEY_UP)
		up();
	else if (in == KEY_DOWN)
		down();
	else if (in == KEY_NPAGE)
		move_rel('d', max( 5, (last_line - 5)));
	else if (in == KEY_PPAGE)
		move_rel('u', max(5, (last_line - 5)));
	else if (in == KEY_DL)
		del_line();
	else if (in == KEY_DC)
		del_char();
	else if (in == KEY_BACKSPACE)
		delete(TRUE);
	else if (in == KEY_IL)
	{		/* insert a line before current line	*/
		insert_line(TRUE);
		left(TRUE);
	}
	else if (in == KEY_F(1))
		gold = !gold;
	else if (in == KEY_F(2))
	{
		if (gold)
		{
			gold = FALSE;
			undel_line();
		}
		else
			undel_char();
	}
	else if (in == KEY_F(3))
	{
		if (gold)
		{
			gold = FALSE;
			undel_word();
		}
		else
			del_word();
	}
	else if (in == KEY_F(4))
	{
		if (gold)
		{
			gold = FALSE;
			paint_info_win();
			midscreen(scr_vert, point);
		}
		else
			adv_word();
	}
	else if (in == KEY_F(5))
	{
		if (gold)
		{
			gold = FALSE;
			search_prompt();
		}
		else
			search(TRUE);
	}
	else if (in == KEY_F(6))
	{
		if (gold)
		{
			gold = FALSE;
			bottom();
		}
		else
			top();
	}
	else if (in == KEY_F(7))
	{
		if (gold)
		{
			gold = FALSE;
			eol();
		}
		else
			bol();
	}
	else if (in == KEY_F(8))
	{
		if (gold)
		{
			gold = FALSE;
			command_prompt();
		} 
		else
			adv_line();
	}
}

void 
command_prompt()
{
	wchar_t *cmd_str;
	int result;

	info_type = COMMANDS;
	paint_info_win();
	cmd_str = get_string(command_str, TRUE);
	if ((result = unique_test(cmd_str, commands)) != 1)
	{
		werase(com_win);
		wmove(com_win, 0, 0);
		if (result == 0)
			wprintw(com_win, unkn_cmd_str, cmd_str);
		else
			wprintw(com_win, "%S", non_unique_cmd_msg);

		wrefresh(com_win);

		info_type = CONTROL_KEYS;
		paint_info_win();

		if (cmd_str != NULL)
			free(cmd_str);
		return;
	}
	command(cmd_str);
	wrefresh(com_win);
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
	info_type = CONTROL_KEYS;
	paint_info_win();
	if (cmd_str != NULL)
		free(cmd_str);
}

void command(wchar_t *cmd_str1)		/* process commands from keyboard	*/
{
	wchar_t *cmd_str2 = NULL;
	wchar_t *cmd_str = cmd_str1;

	clear_com_win = TRUE;
	if (compare(cmd_str, HELP, FALSE))
		help();
	else if (compare(cmd_str, LINE, FALSE))
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, line_num_str, curr_line->line_number);
		wprintw(com_win, line_len_str, curr_line->line_length);
	}
	else if (compare(cmd_str, FILE_str, FALSE))
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		if (in_file_name == NULL)
			wprintw(com_win, no_file_string);
		else
			wprintw(com_win, current_file_str, in_file_name);
	}
	else if ((*cmd_str >= '0') && (*cmd_str <= '9'))
		goto_line(cmd_str);
	else if (compare(cmd_str, CHARACTER, FALSE))
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, char_str, *point);
	}
	else if (compare(cmd_str, REDRAW, FALSE))
		redraw();
	else if (compare(cmd_str, RESEQUENCE, FALSE))
	{
		tmp_line = first_line->next_line;
		while (tmp_line != NULL)
		{
		tmp_line->line_number = tmp_line->prev_line->line_number + 1;
			tmp_line = tmp_line->next_line;
		}
	}
	else if (compare(cmd_str, SAVE, FALSE))
	  write_file(tmp_file, -1);
	else if (compare(cmd_str, AUTHOR, FALSE))
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, "written by Hugh Mahon");
	}
	else if (compare(cmd_str, ee_VERSION, FALSE))
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, "%s", version);
	}
	else if (compare(cmd_str, CASE, FALSE))
		case_sen = TRUE;
	else if (compare(cmd_str, NOCASE, FALSE))
		case_sen = FALSE;
	else if (compare(cmd_str, EXPAND, FALSE))
		expand_tabs = TRUE;
	else if (compare(cmd_str, NOEXPAND, FALSE))
		expand_tabs = FALSE;
	else if (compare(cmd_str, Exit_string, FALSE))
		ee_finish();
	else if (compare(cmd_str, QUIT_string, FALSE))
		quit(0);
	else if ((*cmd_str == '<') && (!in_pipe))
	{
		in_pipe = TRUE;
		cmd_str++;
		if ((*cmd_str == ' ') || (*cmd_str == '\t'))
			cmd_str = next_word((wchar_t*)cmd_str);
		command(cmd_str);
		in_pipe = FALSE;
	}
	else if ((*cmd_str == '>') && (!out_pipe))
	{
		out_pipe = TRUE;
		cmd_str++;
		if ((*cmd_str == ' ') || (*cmd_str == '\t'))
			cmd_str = next_word((wchar_t*)cmd_str);
		command(cmd_str);
		out_pipe = FALSE;
	}
	else
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, unkn_cmd_str, cmd_str);
	}
	if (cmd_str2 != NULL)
		free(cmd_str2);
}

int 
scan(line, offset, column)	/* determine horizontal position for get_string	*/
wchar_t *line;
int offset;
int column;
{
	wchar_t *stemp;
	int i;
	int j;

	stemp = line;
	i = 0;
	j = column;
	while (i < offset)
	{
		i++;
		j += len_char(*stemp, j);
		stemp++;
	}
	return(j);
}

wchar_t *
get_string(prompt, advance)	/* read string from input on command line */
wchar_t *prompt;		/* string containing user prompt message	*/
int advance;		/* if true, skip leading spaces and tabs	*/
{
	wchar_t *string;
	wchar_t *tmp_string;
	wchar_t *nam_str;
	wchar_t *g_point;
	int tmp_int;
	int g_horz, g_position, g_pos;
	int esc_flag;

	g_point = tmp_string = malloc(512 * sizeof(wchar_t));
	wmove(com_win,0,0);
	wclrtoeol(com_win);
	waddwstr(com_win, prompt);
	wrefresh(com_win);
	nam_str = tmp_string;
	clear_com_win = TRUE;
	g_horz = g_position = scan(prompt, wcslen(prompt), 0);
	g_pos = 0;
	do
	{
		int keyt;
		esc_flag = FALSE;
		keyt = wget_wch(com_win, &in);
		if (keyt == ERR)
			exit(0);
		if (keyt == KEY_CODE_YES)
		{
			if (in == KEY_BACKSPACE)
				in = 8;
			else
				continue;
		}
		if (((in == 8) || (in == 127)) && (g_pos > 0))
		{
			tmp_int = g_horz;
			g_pos--;
			g_horz = scan(g_point, g_pos, g_position);
			tmp_int = tmp_int - g_horz;
			for (; 0 < tmp_int; tmp_int--)
			{
				if ((g_horz+tmp_int) < (last_col - 1))
				{
					waddch(com_win, '\010');
					waddch(com_win, ' ');
					waddch(com_win, '\010');
				}
			}
			nam_str--;
		}
		else if ((in != 8) && (in != 127) && (in != '\n') && (in != '\r'))
		{
			if (in == '\026')	/* control-v, accept next character verbatim	*/
			{			/* allows entry of ^m, ^j, and ^h	*/
				int keyt;
				esc_flag = TRUE;
				do
				{
					keyt = wget_wch(com_win, &in);
				
					if (keyt == ERR)
						exit(0);
				} while (keyt != OK);
			}
			*nam_str = in;
			g_pos++;
			if (in < ' ')
				g_horz += out_char(com_win, in, g_horz);
			else
			{
				g_horz++;
				if (g_horz < (last_col - 1))
					waddnwstr(com_win, &in, 1);
			}
			nam_str++;
		}
		wrefresh(com_win);
		if (esc_flag)
			in = '\0';
	} while ((in != '\n') && (in != '\r'));
	*nam_str = '\0';
	nam_str = tmp_string;
	if (((*nam_str == ' ') || (*nam_str == 9)) && (advance))
		nam_str = next_word(nam_str);
	string = malloc((wcslen(nam_str) + 1) * sizeof(wchar_t));
	wcscpy(string, nam_str);
	free(tmp_string);
	wrefresh(com_win);
	return(string);
}

int 
compare(string1, string2, sensitive)	/* compare two strings	*/
wchar_t *string1;
wchar_t *string2;
int sensitive;
{
	wchar_t *strng1;
	wchar_t *strng2;
	int tmp;
	int equal;

	strng1 = string1;
	strng2 = string2;
	tmp = 0;
	if ((strng1 == NULL) || (strng2 == NULL) || (*strng1 == '\0') || (*strng2 == '\0'))
		return(FALSE);
	equal = TRUE;
	while (equal)
	{
		if (sensitive)
		{
			if (*strng1 != *strng2)
				equal = FALSE;
		}
		else
		{
			if (toupper(*strng1) != toupper(*strng2))
				equal = FALSE;
		}
		strng1++;
		strng2++;
		if ((*strng1 == '\0') || (*strng2 == '\0') || (*strng1 == ' ') || (*strng2 == ' '))
			break;
		tmp++;
	}
	return(equal);
}

void goto_line(wchar_t *cmd_str)
{
	int number;
	int i;
	wchar_t *ptr;
	char direction = 0;
	struct text *t_line;

	ptr = cmd_str;
	i= 0;
	while ((*ptr >='0') && (*ptr <= '9'))
	{
		i= i * 10 + (*ptr - '0');
		ptr++;
	}
	number = i;
	i = 0;
	t_line = curr_line;
	while ((t_line->line_number > number) && (t_line->prev_line != NULL))
	{
		i++;
		t_line = t_line->prev_line;
		direction = 'u';
	}
	while ((t_line->line_number < number) && (t_line->next_line != NULL))
	{
		i++;
		direction = 'd';
		t_line = t_line->next_line;
	}
	if ((i < 30) && (i > 0))
	{
		move_rel(direction, i);
	}
	else
	{
		curr_line = t_line;
		point = curr_line->line;
		position = 1;
		midscreen((last_line / 2), point);
		scr_pos = scr_horz;
	}
	wmove(com_win, 0, 0);
	wclrtoeol(com_win);
	wprintw(com_win, line_num_str, curr_line->line_number);
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
}

void 
midscreen(line, pnt)	/* put current line in middle of screen	*/
int line;
wchar_t *pnt;
{
	struct text *mid_line;
	int i;

	line = min(line, last_line);
	mid_line = curr_line;
	for (i = 0; ((i < line) && (curr_line->prev_line != NULL)); i++)
		curr_line = curr_line->prev_line;
	scr_vert = scr_horz = 0;
	wmove(text_win, 0, 0);
	draw_screen();
	scr_vert = i;
	curr_line = mid_line;
	scanline(pnt);
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
}

void 
check_fp()		/* open or close files according to flags */
{
	int line_num;
	int temp;
	struct stat buf;

	clear_com_win = TRUE;
	tmp_vert = scr_vert;
	tmp_horz = scr_horz;
	tmp_line = curr_line;
	if (input_file)
		in_file_name = tmp_file;
	
	temp = stat(tmp_file, &buf);
	buf.st_mode &= ~07777;
	if ((temp != -1) && (buf.st_mode != 0100000) && (buf.st_mode != 0))
	{
		wprintw(com_win, file_is_dir_msg, tmp_file);
		wrefresh(com_win);
		if (input_file)
		{
			quit(0);
			return;
		}
		else
			return;
	}
	if ((get_fd = open(tmp_file, O_RDONLY)) == -1)
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		if (input_file)
			wprintw(com_win, new_file_msg, tmp_file);
		else
			wprintw(com_win, cant_open_msg, tmp_file);
		wrefresh(com_win);
		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
		wrefresh(text_win);
		recv_file = FALSE;
		input_file = FALSE;
		return;
	}
	else
		get_file(tmp_file);

	recv_file = FALSE;
	line_num = curr_line->line_number;
	scr_vert = tmp_vert;
	scr_horz = tmp_horz;
	if (input_file)
		curr_line= first_line;
	else
		curr_line = tmp_line;
	point = curr_line->line;
	draw_screen();
	if (input_file)
	{
		input_file = FALSE;
		if (start_at_line != NULL)
		{
			line_num = watoi(start_at_line) - 1;
			move_rel('d', line_num);
			line_num = 0;
			start_at_line = NULL;
		}
	}
	else
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		text_changes = TRUE;
		if ((tmp_file != NULL) && (*tmp_file != '\0'))
			wprintw(com_win, file_read_fin_msg, tmp_file);
	}
	wrefresh(com_win);
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
	wrefresh(text_win);
}

void 
get_file(file_name)	/* read specified file into current buffer	*/
char *file_name;
{
	int can_read;		/* file has at least one character	*/
	int length;		/* length of line read by read		*/
	int append;		/* should text be appended to current line */
	struct text *temp_line;
	char ro_flag = FALSE;
	char in_string[MAX_FILE+1];

	if (recv_file)		/* if reading a file			*/
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, reading_file_msg, file_name);
		if (access(file_name, 2))	/* check permission to write */
		{
			if ((errno == ENOTDIR) || (errno == EACCES) || (errno == EROFS) || (errno == ETXTBSY) || (errno == EFAULT))
			{
				wprintw(com_win, read_only_msg);
				ro_flag = TRUE;
			}
		}
		wrefresh(com_win);
	}
	if (curr_line->line_length > 1)	/* if current line is not blank	*/
	{
		insert_line(FALSE);
		left(FALSE);
		append = FALSE;
	}
	else
		append = TRUE;
	can_read = FALSE;		/* test if file has any characters  */
	length = read(get_fd, in_string, sizeof(in_string) - 1);
	// in DGL, config files are better capped
	if (length != -1)
	{
		can_read = TRUE;  /* if set file has at least 1 character   */
		in_string[length] = 0;
		get_line(length, in_string, &append);
	}
	if ((can_read) && (curr_line->line_length == 1) && (curr_line->prev_line))
	{
		temp_line = curr_line->prev_line;
		temp_line->next_line = curr_line->next_line;
		if (temp_line->next_line != NULL)
			temp_line->next_line->prev_line = temp_line;
		if (curr_line->line != NULL)
			free(curr_line->line);
		free(curr_line);
		curr_line = temp_line;
	}
	if (input_file)	/* if this is the file to be edited display number of lines	*/
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, file_read_lines_msg, in_file_name, curr_line->line_number);
		if (ro_flag)
			wprintw(com_win, read_only_msg);
		wrefresh(com_win);
	}
	else if (can_read)	/* not input_file and file is non-zero size */
		text_changes = TRUE;

	if (recv_file)		/* if reading a file			*/
	{
		in = EOF;
	}
}

void 
get_line(length, in_str, append)	/* read string and split into lines */
int length;		/* length of string read by read		*/
char *in_str;		/* string read by read				*/
int *append;	/* TRUE if must append more text to end of current line	*/
{
	wchar_t *str1;
	wchar_t *str2;
	int num;		/* offset from start of string		*/
	int char_count;		/* length of new line (or added portion	*/
	int temp_counter;	/* temporary counter value		*/
	struct text *tline;	/* temporary pointer to new line	*/
	int first_time;		/* if TRUE, the first time through the loop */
	wchar_t in_string[MAX_FILE];
	length = mbstowcs(in_string, in_str, sizeof(in_string)/sizeof(wchar_t));

	if (length == -1) {
	    wmove(com_win, 0, 0);
	    wprintw(com_win, "ERROR: Encountered a strange character. --more--");
	    wclrtoeol(com_win);
	    wrefresh(com_win);
	    (void) wget_wch(com_win, &in);
	    resetty();
	    endwin();
	    exit(0);
	}

	str2 = in_string;
	num = 0;
	first_time = TRUE;
	while (num < length)
	{
		if (!first_time)
		{
			if (num < length)
			{
				str2++;
				num++;
			}
		}
		else
			first_time = FALSE;
		str1 = str2;
		char_count = 1;
		/* find end of line	*/
		while ((*str2 != '\n') && (num < length))
		{
			str2++;
			num++;
			char_count++;
		}
		if (!(*append))	/* if not append to current line, insert new one */
		{
			tline = txtalloc();	/* allocate data structure for next line */
			tline->line_number = curr_line->line_number + 1;
			tline->next_line = curr_line->next_line;
			tline->prev_line = curr_line;
			curr_line->next_line = tline;
			if (tline->next_line != NULL)
				tline->next_line->prev_line = tline;
			curr_line = tline;
			curr_line->line = point = (wchar_t *) malloc(char_count * sizeof(wchar_t));
			curr_line->line_length = char_count;
			curr_line->max_length = char_count;
		}
		else
		{
			point = resiz_line(char_count, curr_line, curr_line->line_length); 
			curr_line->line_length += (char_count - 1);
		}
		for (temp_counter = 1; temp_counter < char_count; temp_counter++)
		{
			*point = *str1;
			point++;
			str1++;
		}
		*point = '\0';
		*append = FALSE;
		if ((num == length) && (*str2 != '\n'))
			*append = TRUE;
	}
}

void 
draw_screen()		/* redraw the screen from current postion	*/
{
	struct text *temp_line;
	wchar_t *line_out;
	int temp_vert;

	temp_line = curr_line;
	temp_vert = scr_vert;
	wclrtobot(text_win);
	while ((temp_line != NULL) && (temp_vert <= last_line))
	{
		line_out = temp_line->line;
		draw_line(temp_vert, 0, line_out, 1, temp_line->line_length);
		temp_vert++;
		temp_line = temp_line->next_line;
	}
	wmove(text_win, temp_vert, 0);
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
}

void 
ee_finish()	/* prepare to exit edit session	*/
{
	char *file_name = in_file_name;

	/*
	 |	changes made here should be reflected in the 'save' 
	 |	portion of file_op()
	 */

//	if ((file_name == NULL) || (*file_name == '\0'))
//		file_name = get_string(save_file_name_prompt, TRUE);

	if ((file_name == NULL) || (*file_name == '\0'))
	{
		wmove(com_win, 0, 0);
		wprintw(com_win, file_not_saved_msg);
		wclrtoeol(com_win);
		wrefresh(com_win);
		clear_com_win = TRUE;
		return;
	}

	if (write_file(file_name, -1))
	{
		text_changes = FALSE;
		quit(0);
	}
}

int 
quit(noverify)		/* exit editor			*/
int noverify;
{
	wchar_t *ans;

	touchwin(text_win);
	wrefresh(text_win);
	if ((text_changes) && (!noverify))
	{
		ans = get_string(changes_made_prompt, TRUE);
		if (toupper(*ans) == toupper(*yes_char))
			text_changes = FALSE;
		else
			return(0);
		free(ans);
	}
	
	if (info_window)
	  wrefresh(info_win);
	wrefresh(com_win);
	resetty();
	endwin();
	putchar('\n');
	exit(0);
}

void 
edit_abort(arg)
int arg;
{
	wrefresh(com_win);
	resetty();
	endwin();
	putchar('\n');
	exit(1);
}

void 
delete_text()
{
	while (curr_line->next_line != NULL)
		curr_line = curr_line->next_line;
	while (curr_line != first_line)
	{
		free(curr_line->line);
		curr_line = curr_line->prev_line;
		free(curr_line->next_line);
	}
	curr_line->next_line = NULL;
	*curr_line->line = '\0';
	curr_line->line_length = 1;
	curr_line->line_number = 1;
	point = curr_line->line;
	scr_pos = scr_vert = scr_horz = 0;
	position = 1;
}

/* If fd >= 0, then use the previously opened file. This is a 
   hack to get safe tempfile handling in ispell.*/
int write_file(char *file_name, int fd)
{
	wchar_t cr;
	wchar_t *tmp_point;
	struct text *out_line;
	int lines, charac;
	int temp_pos;
	int write_flag = TRUE;

	charac = lines = 0;
	if ((fd < 0) &&
            ((in_file_name == NULL) || strcmp(in_file_name, file_name)))
	{
		if ((temp_fp = fopen(file_name, "r")))
		{
			tmp_point = get_string(file_exists_prompt, TRUE);
			if (toupper(*tmp_point) == toupper(*yes_char))
				write_flag = TRUE;
			else 
				write_flag = FALSE;
			fclose(temp_fp);
			free(tmp_point);
		}
	}

	clear_com_win = TRUE;

	if (write_flag)
	{
                if (fd < 0) 
                {
                        temp_fp = fopen(file_name, "w");
                }
                else
                {
                        temp_fp = fdopen(fd, "w");
                }

		if (temp_fp == NULL)
		{
			clear_com_win = TRUE;
			wmove(com_win,0,0);
			wclrtoeol(com_win);
			wprintw(com_win, create_file_fail_msg, file_name);
			wrefresh(com_win);
			return(FALSE);
		}
		else
		{
			wmove(com_win,0,0);
			wclrtoeol(com_win);
			wprintw(com_win, writing_file_msg, file_name);
			wrefresh(com_win);
			cr = '\n';
			out_line = first_line;
			while (out_line != NULL)
			{
				temp_pos = 1;
				tmp_point= out_line->line;
				while (temp_pos < out_line->line_length)
				{
					fputwc(*tmp_point, temp_fp);
					tmp_point++;
					temp_pos++;
				}
				charac += out_line->line_length;
				out_line = out_line->next_line;
				fputwc(cr, temp_fp);
				lines++;
			}
			fclose(temp_fp);
			wmove(com_win,0,0);
			wclrtoeol(com_win);
			wprintw(com_win, file_written_msg, file_name, lines, charac);
			wrefresh(com_win);
			return(TRUE);
		}
	}
	else
		return(FALSE);
}

int 
search(display_message)		/* search for string in srch_str	*/
int display_message;
{
	int lines_moved;
	int iter;
	int found;

	if ((srch_str == NULL) || (*srch_str == '\0'))
		return(FALSE);
	if (display_message)
	{
		wmove(com_win, 0, 0);
		wclrtoeol(com_win);
		wprintw(com_win, searching_msg);
		wrefresh(com_win);
		clear_com_win = TRUE;
	}
	lines_moved = 0;
	found = FALSE;
	srch_line = curr_line;
	srch_1 = point;
	if (position < curr_line->line_length)
		srch_1++;
	iter = position + 1;
	while ((!found) && (srch_line != NULL))
	{
		while ((iter < srch_line->line_length) && (!found))
		{
			srch_2 = srch_1;
			if (case_sen)	/* if case sensitive		*/
			{
				srch_3 = srch_str;
			while ((*srch_2 == *srch_3) && (*srch_3 != '\0'))
				{
					found = TRUE;
					srch_2++;
					srch_3++;
				}	/* end while	*/
			}
			else		/* if not case sensitive	*/
			{
				srch_3 = u_srch_str;
			while ((toupper(*srch_2) == *srch_3) && (*srch_3 != '\0'))
				{
					found = TRUE;
					srch_2++;
					srch_3++;
				}
			}	/* end else	*/
			if (!((*srch_3 == '\0') && (found)))
			{
				found = FALSE;
				if (iter < srch_line->line_length)
					srch_1++;
				iter++;
			}
		}
		if (!found)
		{
			srch_line = srch_line->next_line;
			if (srch_line != NULL)
				srch_1 = srch_line->line;
			iter = 1;
			lines_moved++;
		}
	}
	if (found)
	{
		if (display_message)
		{
			wmove(com_win, 0, 0);
			wclrtoeol(com_win);
			wrefresh(com_win);
		}
		if (lines_moved == 0)
		{
			while (position < iter)
				right(TRUE);
		}
		else
		{
			if (lines_moved < 30)
			{
				move_rel('d', lines_moved);
				while (position < iter)
					right(TRUE);
			}
			else 
			{
				curr_line = srch_line;
				point = srch_1;
				position = iter;
				scanline(point);
				scr_pos = scr_horz;
				midscreen((last_line / 2), point);
			}
		}
	}
	else
	{
		if (display_message)
		{
			wmove(com_win, 0, 0);
			wclrtoeol(com_win);
			wprintw(com_win, str_not_found_msg, srch_str);
			wrefresh(com_win);
		}
		wmove(text_win, scr_vert,(scr_horz - horiz_offset));
	}
	return(found);
}

void 
search_prompt()		/* prompt and read search string (srch_str)	*/
{
	if (srch_str != NULL)
		free(srch_str);
	if ((u_srch_str != NULL) && (*u_srch_str != '\0'))
		free(u_srch_str);
	srch_str = get_string(search_prompt_str, FALSE);
	gold = FALSE;
	srch_3 = srch_str;
	srch_1 = u_srch_str = (wchar_t*)malloc((wcslen(srch_str) + 1) * sizeof(wchar_t));
	while (*srch_3 != '\0')
	{
		*srch_1 = toupper(*srch_3);
		srch_1++;
		srch_3++;
	}
	*srch_1 = '\0';
	search(TRUE);
}

void 
del_char()			/* delete current character	*/
{
	in = 8;  /* backspace */
	if (position < curr_line->line_length)	/* if not end of line	*/
	{
		if ((*point > 127) && ((curr_line->line_length - position) >= 2))
		{
			point++;
			position++;
		}
		position++;
		point++;
		scanline(point);
		delete(TRUE);
	}
	else
	{
		right(FALSE);
		delete(FALSE);
	}
}

void 
undel_char()			/* undelete last deleted character	*/
{
	if (d_char[0] == '\n')	/* insert line if last del_char deleted eol */
		insert_line(TRUE);
	else
	{
		in = d_char[0];
		insert(in);
		if (d_char[1] != '\0')
		{
			in = d_char[1];
			insert(in);
		}
	}
}

void 
del_word()			/* delete word in front of cursor	*/
{
	int tposit;
	int difference;
	wchar_t *d_word2;
	wchar_t *d_word3;
	wchar_t tmp_char[3];

	if (d_word != NULL)
		free(d_word);
	d_word = (wchar_t*)malloc(curr_line->line_length * sizeof(wchar_t));
	tmp_char[0] = d_char[0];
	tmp_char[1] = d_char[1];
	tmp_char[2] = d_char[2];
	d_word3 = point;
	d_word2 = d_word;
	tposit = position;
	while ((tposit < curr_line->line_length) && 
				((*d_word3 != ' ') && (*d_word3 != '\t')))
	{
		tposit++;
		*d_word2 = *d_word3;
		d_word2++;
		d_word3++;
	}
	while ((tposit < curr_line->line_length) && 
				((*d_word3 == ' ') || (*d_word3 == '\t')))
	{
		tposit++;
		*d_word2 = *d_word3;
		d_word2++;
		d_word3++;
	}
	*d_word2 = '\0';
	d_wrd_len = difference = d_word2 - d_word;
	d_word2 = point;
	while (tposit < curr_line->line_length)
	{
		tposit++;
		*d_word2 = *d_word3;
		d_word2++;
		d_word3++;
	}
	curr_line->line_length -= difference;
	*d_word2 = '\0';
	draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
	d_char[0] = tmp_char[0];
	d_char[1] = tmp_char[1];
	d_char[2] = tmp_char[2];
	text_changes = TRUE;
	formatted = FALSE;
}

void 
undel_word()		/* undelete last deleted word		*/
{
	int temp;
	int tposit;
	wchar_t *tmp_old_ptr;
	wchar_t *tmp_space;
	wchar_t *tmp_ptr;
	wchar_t *d_word_ptr;

	/*
	 |	resize line to handle undeleted word
	 */
	if ((curr_line->max_length - (curr_line->line_length + d_wrd_len)) < 5)
		point = resiz_line(d_wrd_len, curr_line, position);
	tmp_ptr = tmp_space = (wchar_t*)malloc((curr_line->line_length + d_wrd_len) * sizeof(wchar_t));
	d_word_ptr = d_word;
	temp = 1;
	/*
	 |	copy d_word contents into temp space
	 */
	while (temp <= d_wrd_len)
	{
		temp++;
		*tmp_ptr = *d_word_ptr;
		tmp_ptr++;
		d_word_ptr++;
	}
	tmp_old_ptr = point;
	tposit = position;
	/*
	 |	copy contents of line from curent position to eol into 
	 |	temp space
	 */
	while (tposit < curr_line->line_length)
	{
		temp++;
		tposit++;
		*tmp_ptr = *tmp_old_ptr;
		tmp_ptr++;
		tmp_old_ptr++;
	}
	curr_line->line_length += d_wrd_len;
	tmp_old_ptr = point;
	*tmp_ptr = '\0';
	tmp_ptr = tmp_space;
	tposit = 1;
	/*
	 |	now copy contents from temp space back to original line
	 */
	while (tposit < temp)
	{
		tposit++;
		*tmp_old_ptr = *tmp_ptr;
		tmp_ptr++;
		tmp_old_ptr++;
	}
	*tmp_old_ptr = '\0';
	free(tmp_space);
	draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
}

void 
del_line()			/* delete from cursor to end of line	*/
{
	wchar_t *dl1;
	wchar_t *dl2;
	int tposit;

	if (d_line != NULL)
		free(d_line);
	d_line = (wchar_t*)malloc(curr_line->line_length * sizeof(wchar_t));
	dl1 = d_line;
	dl2 = point;
	tposit = position;
	while (tposit < curr_line->line_length)
	{
		*dl1 = *dl2;
		dl1++;
		dl2++;
		tposit++;
	}
	dlt_line->line_length = 1 + tposit - position;
	*dl1 = *point = '\0';
	curr_line->line_length = position;
	wclrtoeol(text_win);
	if (curr_line->next_line != NULL)
	{
		right(FALSE);
		delete(FALSE);
	}
	text_changes = TRUE;
}

void 
undel_line()			/* undelete last deleted line		*/
{
	wchar_t *ud1;
	wchar_t *ud2;
	int tposit;

	if (dlt_line->line_length == 0)
		return;

	insert_line(TRUE);
	left(TRUE);
	point = resiz_line(dlt_line->line_length, curr_line, position);
	curr_line->line_length += dlt_line->line_length - 1;
	ud1 = point;
	ud2 = d_line;
	tposit = 1;
	while (tposit < dlt_line->line_length)
	{
		tposit++;
		*ud1 = *ud2;
		ud1++;
		ud2++;
	}
	*ud1 = '\0';
	draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
}

void 
adv_word()			/* advance to next word		*/
{
while ((position < curr_line->line_length) && ((*point != 32) && (*point != 9)))
		right(TRUE);
while ((position < curr_line->line_length) && ((*point == 32) || (*point == 9)))
		right(TRUE);
}

void move_rel(char direction, int lines)	/* move relative to current line	*/
{
	int i;
	wchar_t *tmp;

	if (direction == 'u')
	{
		scr_pos = 0;
		while (position > 1)
			left(TRUE);
		for (i = 0; i < lines; i++)
		{
			up();
		}
		if ((last_line > 5) && ( scr_vert < 4))
		{
			tmp = point;
			tmp_line = curr_line;
			for (i= 0;(i<5)&&(curr_line->prev_line != NULL); i++)
			{
				up();
			}
			scr_vert = scr_vert + i;
			curr_line = tmp_line;
			point = tmp;
			scanline(point);
		}
	}
	else
	{
		if ((position != 1) && (curr_line->next_line != NULL))
		{
			nextline();
			scr_pos = scr_horz = 0;
			if (horiz_offset)
			{
				horiz_offset = 0;
				midscreen(scr_vert, point);
			}
		}
		else
			adv_line();
		for (i = 1; i < lines; i++)
		{
			down();
		}
		if ((last_line > 10) && (scr_vert > (last_line - 5)))
		{
			tmp = point;
			tmp_line = curr_line;
			for (i=0; (i<5) && (curr_line->next_line != NULL); i++)
			{
				down();
			}
			scr_vert = scr_vert - i;
			curr_line = tmp_line;
			point = tmp;
			scanline(point);
		}
	}
	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
}

void 
eol()				/* go to end of line			*/
{
	if (position < curr_line->line_length)
	{
		while (position < curr_line->line_length)
			right(TRUE);
	}
	else if (curr_line->next_line != NULL)
	{
		right(TRUE);
		while (position < curr_line->line_length)
			right(TRUE);
	}
}

void 
bol()				/* move to beginning of line	*/
{
	if (point != curr_line->line)
	{
		while (point != curr_line->line)
			left(TRUE);
	}
	else if (curr_line->prev_line != NULL)
	{
		scr_pos = 0;
		up();
	}
}

void 
adv_line()	/* advance to beginning of next line	*/
{
	if ((point != curr_line->line) || (scr_pos > 0))
	{
		while (position < curr_line->line_length)
			right(TRUE);
		right(TRUE);
	}
	else if (curr_line->next_line != NULL)
	{
		scr_pos = 0;
		down();
	}
}

void 
set_up_term()		/* set up the terminal for operating with ae	*/
{
	if (!curses_initialized)
	{
		initscr();
		savetty();
		noecho();
		raw();
		nonl();
		curses_initialized = TRUE;
	}

	if (((LINES > 15) && (COLS >= 80)) && info_window)
		last_line = LINES - 8;
	else
	{
		info_window = FALSE;
		last_line = LINES - 2;
	}

	idlok(stdscr, TRUE);
	com_win = newwin(1, COLS, (LINES - 1), 0);
	keypad(com_win, TRUE);
	idlok(com_win, TRUE);
	wrefresh(com_win);
	if (!info_window)
		text_win = newwin((LINES - 1), COLS, 0, 0);
	else
		text_win = newwin((LINES - 7), COLS, 6, 0);
	keypad(text_win, TRUE);
	idlok(text_win, TRUE);
	wrefresh(text_win);
	help_win = newwin((LINES - 1), COLS, 0, 0);
	keypad(help_win, TRUE);
	idlok(help_win, TRUE);
	if (info_window)
	{
		info_type = CONTROL_KEYS;
		info_win = newwin(6, COLS, 0, 0);
		werase(info_win);
		paint_info_win();
	}

	last_col = COLS - 1;
	local_LINES = LINES;
	local_COLS = COLS;
}

void 
resize_check()
{
	if ((LINES == local_LINES) && (COLS == local_COLS))
		return;

	if (info_window)
		delwin(info_win);
	delwin(text_win);
	delwin(com_win);
	delwin(help_win);
	set_up_term();
	redraw();
	wrefresh(text_win);
}

static char item_alpha[] = "abcdefghijklmnopqrstuvwxyz0123456789 ";

int menu_op(struct menu_entries menu_list[])
{
	WINDOW *temp_win;
	int max_width, max_height;
	int x_off, y_off;
	int counter;
	int length;
	int input;
	int temp = 0;
	int list_size;
	int top_offset;		/* offset from top where menu items start */
	int vert_size;		/* vertical size for menu list item display */
	int off_start = 1;	/* offset from start of menu items to start display */


	/*
	 |	determine number and width of menu items
	 */

	list_size = 1;
	while (menu_list[list_size + 1].item_string != NULL)
		list_size++;
	max_width = 0;
	for (counter = 0; counter <= list_size; counter++)
	{
		if ((length = wcslen(menu_list[counter].item_string)) > max_width)
			max_width = length;
	}
	max_width += 3;
	max_width = max(max_width, wcslen(menu_cancel_msg));
	max_width = max(max_width, max(wcslen(more_above_str), wcslen(more_below_str)));
	max_width += 6;

	/*
	 |	make sure that window is large enough to handle menu
	 |	if not, print error message and return to calling function
	 */

	if (max_width > COLS)
	{
		wmove(com_win, 0, 0);
		werase(com_win);
		wprintw(com_win, menu_too_lrg_msg);
		wrefresh(com_win);
		clear_com_win = TRUE;
		return(0);
	}

	top_offset = 0;

	if (list_size > LINES)
	{
		max_height = LINES;
		if (max_height > 11)
			vert_size = max_height - 8;
		else
			vert_size = max_height;
	}
	else
	{
		vert_size = list_size;
		max_height = list_size;
	}

	if (LINES >= (vert_size + 8))
	{
		if (menu_list[0].argument != MENU_WARN)
			max_height = vert_size + 8;
		else
			max_height = vert_size + 7;
		top_offset = 4;
	}
	x_off = (COLS - max_width) / 2;
	y_off = (LINES - max_height - 1) / 2;
	temp_win = newwin(max_height, max_width, y_off, x_off);
	keypad(temp_win, TRUE);

	paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size);

	counter = 1;
	do
	{
		int keyt;
		if (off_start > 2)
			wmove(temp_win, (1 + counter + top_offset - off_start), 3);
		else
			wmove(temp_win, (counter + top_offset - off_start), 3);

		wrefresh(temp_win);
		keyt = wget_wch(temp_win, &in);
		input = in;
		if (keyt == ERR)
			exit(0);

		if (keyt == OK && isalnum(tolower(input)))
		{
			if (isalpha(tolower(input)))
			{
				temp = 1 + tolower(input) - 'a';
			}
			else if (isdigit(input))
			{
				temp = (2 + 'z' - 'a') + (input - '0');
			}

			if (temp <= list_size)
			{
				input = '\n';
				counter = temp;
			}
		}
		else if (keyt == OK)
		{
			switch (input)
			{
				case ' ':	/* space	*/
				case '\004':	/* ^d, down	*/
					counter++;
					if (counter > list_size)
						counter = 1;
					break;
				case '\010':	/* ^h, backspace*/
				case '\025':	/* ^u, up	*/
				case 127:	/* ^?, delete	*/
					counter--;
					if (counter == 0)
						counter = list_size;
					break;
				case '\033':	/* escape key	*/
					if (menu_list[0].argument != MENU_WARN)
						counter = 0;
					break;
				case '\014':	/* ^l       	*/
				case '\022':	/* ^r, redraw	*/
					paint_menu(menu_list, max_width, max_height, 
						list_size, top_offset, temp_win, 
						off_start, vert_size);
					break;
				default:
					break;
			}
		}
		else
		{
			switch (input)
			{
				case KEY_RIGHT:
				case KEY_DOWN:
					counter++;
					if (counter > list_size)
						counter = 1;
					break;
				case 127:	/* ^?, delete	*/
				case KEY_BACKSPACE:
				case KEY_LEFT:
				case KEY_UP:
					counter--;
					if (counter == 0)
						counter = list_size;
					break;
				case '\033':	/* escape key	*/
					if (menu_list[0].argument != MENU_WARN)
						counter = 0;
					break;
				case '\014':	/* ^l       	*/
				case '\022':	/* ^r, redraw	*/
					paint_menu(menu_list, max_width, max_height, 
						list_size, top_offset, temp_win, 
						off_start, vert_size);
					break;
				default:
					break;
			}
		}
	
		if (((list_size - off_start) >= (vert_size - 1)) && 
			(counter > (off_start + vert_size - 3)) && 
				(off_start > 1))
		{
			if (counter == list_size)
				off_start = (list_size - vert_size) + 2;
			else
				off_start++;

			paint_menu(menu_list, max_width, max_height, 
				   list_size, top_offset, temp_win, off_start, 
				   vert_size);
		}
		else if ((list_size != vert_size) && 
				(counter > (off_start + vert_size - 2)))
		{
			if (counter == list_size)
				off_start = 2 + (list_size - vert_size);
			else if (off_start == 1)
				off_start = 3;
			else
				off_start++;

			paint_menu(menu_list, max_width, max_height, 
				   list_size, top_offset, temp_win, off_start, 
				   vert_size);
		}
		else if (counter < off_start)
		{
			if (counter <= 2)
				off_start = 1;
			else
				off_start = counter;

			paint_menu(menu_list, max_width, max_height, 
				   list_size, top_offset, temp_win, off_start, 
				   vert_size);
		}
	}
	while ((input != '\r') && (input != '\n') && (counter != 0));

	werase(temp_win);
	wrefresh(temp_win);
	delwin(temp_win);

	if ((menu_list[counter].procedure != NULL) || 
	    (menu_list[counter].iprocedure != NULL) || 
	    (menu_list[counter].nprocedure != NULL))
	{
		if (menu_list[counter].argument != -1)
			(*menu_list[counter].iprocedure)(menu_list[counter].argument);
		else if (menu_list[counter].ptr_argument != NULL)
			(*menu_list[counter].procedure)(menu_list[counter].ptr_argument);
		else
			(*menu_list[counter].nprocedure)();
	}

	if (info_window)
		paint_info_win();
	redraw();

	return(counter);
}

void 
paint_menu(menu_list, max_width, max_height, list_size, top_offset, menu_win, 
	   off_start, vert_size)
struct menu_entries menu_list[];
int max_width, max_height, list_size, top_offset;
WINDOW *menu_win;
int off_start, vert_size;
{
	int counter, temp_int;

	werase(menu_win);

	/*
	 |	output top and bottom portions of menu box only if window 
	 |	large enough 
	 */

	if (max_height > vert_size)
	{
		wmove(menu_win, 1, 1);
		if (!nohighlight)
			wstandout(menu_win);
		waddch(menu_win, '+');
		for (counter = 0; counter < (max_width - 4); counter++)
			waddch(menu_win, '-');
		waddch(menu_win, '+');

		wmove(menu_win, (max_height - 2), 1);
		waddch(menu_win, '+');
		for (counter = 0; counter < (max_width - 4); counter++)
			waddch(menu_win, '-');
		waddch(menu_win, '+');
		wstandend(menu_win);
		wmove(menu_win, 2, 3);
		waddwstr(menu_win, menu_list[0].item_string);
		wmove(menu_win, (max_height - 3), 3);
		if (menu_list[0].argument != MENU_WARN)
			waddwstr(menu_win, menu_cancel_msg);
	}
	if (!nohighlight)
		wstandout(menu_win);

	for (counter = 0; counter < (vert_size + top_offset); counter++)
	{
		if (top_offset == 4)
		{
			temp_int = counter + 2;
		}
		else
			temp_int = counter;

		wmove(menu_win, temp_int, 1);
		waddch(menu_win, '|');
		wmove(menu_win, temp_int, (max_width - 2));
		waddch(menu_win, '|');
	}
	wstandend(menu_win);

	if (list_size > vert_size)
	{
		if (off_start >= 3)
		{
			temp_int = 1;
			wmove(menu_win, top_offset, 3);
			waddwstr(menu_win, more_above_str);
		}
		else
			temp_int = 0;

		for (counter = off_start; 
			((temp_int + counter - off_start) < (vert_size - 1));
				counter++)
		{
			wmove(menu_win, (top_offset + temp_int + 
						(counter - off_start)), 3);
			if (list_size > 1)
				wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
			waddwstr(menu_win, menu_list[counter].item_string);
		}

		wmove(menu_win, (top_offset + (vert_size - 1)), 3);

		if (counter == list_size)
		{
			if (list_size > 1)
				wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
			waddwstr(menu_win, menu_list[counter].item_string);
		}
		else
			waddwstr(menu_win, more_below_str);
	}
	else
	{
		for (counter = 1; counter <= list_size; counter++)
		{
			wmove(menu_win, (top_offset + counter - 1), 3);
			if (list_size > 1)
				wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
			waddwstr(menu_win, menu_list[counter].item_string);
		}
	}
}

void 
help()
{
	int counter, dummy;

	werase(help_win);
	clearok(help_win, TRUE);
	for (counter = 0; counter < 22; counter++)
	{
		wmove(help_win, counter, 0);
		waddwstr(help_win, (emacs_keys_mode) ? 
			emacs_help_text[counter] : help_text[counter]);
	}
	wrefresh(help_win);
	werase(com_win);
	wmove(com_win, 0, 0);
	waddwstr(com_win, press_any_key_msg);
	wrefresh(com_win);
	counter = wget_wch(com_win, &dummy);
	if (counter == ERR)
		exit(0);
	werase(com_win);
	wmove(com_win, 0, 0);
	werase(help_win);
	wrefresh(help_win);
	wrefresh(com_win);
	redraw();
}

void 
paint_info_win()
{
	int counter;

	if (!info_window)
		return;

	werase(info_win);
	for (counter = 0; counter < 5; counter++)
	{
		wmove(info_win, counter, 0);
		wclrtoeol(info_win);
		if (info_type == CONTROL_KEYS)
			waddwstr(info_win, (emacs_keys_mode) ? 
			  emacs_control_keys[counter] : control_keys[counter]);
		else if (info_type == COMMANDS)
			waddwstr(info_win, command_strings[counter]);
	}
	wmove(info_win, 5, 0);
	if (!nohighlight)
		wstandout(info_win);
	waddstr(info_win, "===============================================================================");
	wstandend(info_win);
	wrefresh(info_win);
}

void 
no_info_window()
{
	if (!info_window)
		return;
	delwin(info_win);
	delwin(text_win);
	info_window = FALSE;
	last_line = LINES - 2;
	text_win = newwin((LINES - 1), COLS, 0, 0);
	keypad(text_win, TRUE);
	idlok(text_win, TRUE);
	clearok(text_win, TRUE);
	midscreen(scr_vert, point);
	wrefresh(text_win);
	clear_com_win = TRUE;
}

void 
create_info_window()
{
	if (info_window)
		return;
	last_line = LINES - 8;
	delwin(text_win);
	text_win = newwin((LINES - 7), COLS, 6, 0);
	keypad(text_win, TRUE);
	idlok(text_win, TRUE);
	werase(text_win);
	info_window = TRUE;
	info_win = newwin(6, COLS, 0, 0);
	werase(info_win);
	info_type = CONTROL_KEYS;
	midscreen(min(scr_vert, last_line), point);
	clearok(info_win, TRUE);
	paint_info_win();
	wrefresh(text_win);
	clear_com_win = TRUE;
}

int 
file_op(arg)
int arg;
{
	char *string;
	int flag;

	if (arg == SAVE_FILE)
	{
	/*
	 |	changes made here should be reflected in ee_finish()
	 */

		if (in_file_name)
			flag = TRUE;
		else
			flag = FALSE;

		string = in_file_name;
//		if ((string == NULL) || (*string == '\0'))
//			string = get_string(save_file_name_prompt, TRUE);
		if ((string == NULL) || (*string == '\0'))
		{
			wmove(com_win, 0, 0);
			wprintw(com_win, file_not_saved_msg);
			wclrtoeol(com_win);
			wrefresh(com_win);
			clear_com_win = TRUE;
			return(0);
		}
		if (write_file(string, -1))
		{
			in_file_name = string;
			text_changes = FALSE;
		}
		else if (!flag)
			free(string);
	}
	return(0);
}

void 
leave_op()
{
	if (text_changes)
	{
		menu_op(leave_menu);
	}
	else
		quit(TRUE);
}

void 
redraw()
{
	if (info_window)
        {
                clearok(info_win, TRUE);
        	paint_info_win();
        }
        else
		clearok(text_win, TRUE);
	midscreen(scr_vert, point);
}

/*
 |	The following routines will "format" a paragraph (as defined by a 
 |	block of text with blank lines before and after the block).
 */

int 
Blank_Line(test_line)	/* test if line has any non-space characters	*/
struct text *test_line;
{
	wchar_t *line;
	int length;
	
	if (test_line == NULL)
		return(TRUE);

	length = 1;
	line = test_line->line;

	/*
	 |	To handle troff/nroff documents, consider a line with a 
	 |	period ('.') in the first column to be blank.  To handle mail 
	 |	messages with included text, consider a line with a '>' blank.
	 */

	if ((*line == '.') || (*line == '>'))
		return(TRUE);

	while (((*line == ' ') || (*line == '\t')) && (length < test_line->line_length))
	{
		length++;
		line++;
	}
	if (length != test_line->line_length)
		return(FALSE);
	else
		return(TRUE);
}

void 
echo_string(string)	/* echo the given string	*/
wchar_t *string;
{
	wchar_t *temp;
	int Counter;

		temp = string;
		while (*temp != '\0')
		{
			if (*temp == '\\')
			{
				temp++;
				if (*temp == 'n')
					putchar('\n');
				else if (*temp == 't')
					putchar('\t');
				else if (*temp == 'b')
					putchar('\b');
				else if (*temp == 'r')
					putchar('\r');
				else if (*temp == 'f')
					putchar('\f');
				else if ((*temp == 'e') || (*temp == 'E'))
					putchar('\033');	/* escape */
				else if (*temp == '\\')
					putchar('\\');
				else if (*temp == '\'')
					putchar('\'');
				else if ((*temp >= '0') && (*temp <= '9'))
				{
					Counter = 0;
					while ((*temp >= '0') && (*temp <= '9'))
					{
						Counter = (8 * Counter) + (*temp - '0');
						temp++;
					}
					putchar(Counter);
					temp--;
				}
				temp++;
			}
			else
			{
				putchar(*temp);
				temp++;
			}
		}

	fflush(stdout);
}

int
first_word_len(test_line)
struct text *test_line;
{
	int counter;
	wchar_t *pnt;

	if (test_line == NULL)
		return(0);

	pnt = test_line->line;
	if ((pnt == NULL) || (*pnt == '\0') || 
	    (*pnt == '.') || (*pnt == '>'))
		return(0);

	if ((*pnt == ' ') || (*pnt == '\t'))
	{
		pnt = next_word(pnt);
	}

	if (*pnt == '\0')
		return(0);

	counter = 0;
	while ((*pnt != '\0') && ((*pnt != ' ') && (*pnt != '\t')))
	{
		pnt++;
		counter++;
	}
	while ((*pnt != '\0') && ((*pnt == ' ') || (*pnt == '\t')))
	{
		pnt++;
		counter++;
	}
	return(counter);
}

wchar_t *
is_in_string(string, substring)	/* a strchr() look-alike for systems without
				   strchr() */
wchar_t * string, *substring;
{
	wchar_t *full, *sub;

	for (sub = substring; (sub != NULL) && (*sub != '\0'); sub++)
	{
		for (full = string; (full != NULL) && (*full != '\0'); 
				full++)
		{
			if (*sub == *full)
				return(full);
		}
	}
	return(NULL);
}

/*
 |	The following routine tests the input string against the list of 
 |	strings, to determine if the string is a unique match with one of the 
 |	valid values.
 */

int 
unique_test(string, list)
wchar_t *string;
wchar_t *list[];
{
	int counter;
	int num_match;
	int result;

	num_match = 0;
	counter = 0;
	while (list[counter] != NULL)
	{
		result = compare(string, list[counter], FALSE);
		if (result)
			num_match++;
		counter++;
	}
	return(num_match);
}

/*
 |	The following is to allow for using message catalogs which allow 
 |	the software to be 'localized', that is, to use different languages 
 |	all with the same binary.  For more information, see your system 
 |	documentation, or the X/Open Internationalization Guide.
 */

void 
strings_init()
{
	leave_menu[0].item_string  = L"leave menu";
	leave_menu[1].item_string  = L"save changes";
	leave_menu[2].item_string  = L"no save";
	search_menu[0].item_string = L"search menu";
	search_menu[1].item_string = L"search for ...";
	search_menu[2].item_string = L"search";
	main_menu[0].item_string  = L"main menu";
	main_menu[1].item_string  = L"leave editor";
	main_menu[2].item_string  = L"help";
	main_menu[3].item_string  = L"save file";
	main_menu[4].item_string  = L"redraw screen";
	main_menu[5].item_string  = L"search";
	help_text[0] = L"Control keys:                                                              "; 
	help_text[1] = L"^a ascii code           ^i tab                  ^r right                   ";
	help_text[2] = L"^b bottom of text       ^j newline              ^t top of text             ";
	help_text[3] = L"^c command              ^k delete char          ^u up                      ";
	help_text[4] = L"^d down                 ^l left                 ^v undelete word           ";
	help_text[5] = L"^e search prompt        ^m newline              ^w delete word             ";
	help_text[6] = L"^f undelete char        ^n next page            ^x search                  ";
	help_text[7] = L"^g begin of line        ^o end of line          ^y delete line             ";
	help_text[8] = L"^h backspace            ^p prev page            ^z undelete line           ";
	help_text[9] = L"^[ (escape) menu                                                           ";
	help_text[10] = L"                                                                           ";
	help_text[11] = L"Commands:                                                                  ";
	help_text[12] = L"help    : get this info                 file    : print file name          ";
	help_text[13] = L"read    : (disabled)                    char    : ascii code of char       ";
	help_text[14] = L"write   : (disabled)                    case    : case sensitive search    ";
	help_text[15] = L"exit    : leave and save                nocase  : case insensitive search  ";
	help_text[16] = L"quit    : leave, no save                !cmd    : (disabled)               ";
	help_text[17] = L"line    : display line #                0-9     : go to line \"#\"           ";
	help_text[18] = L"expand  : expand tabs                   noexpand: do not expand tabs         ";
	help_text[19] = L"                                                                             ";
	help_text[20] = L"  ee [+#] [-i] [-e] [-h] [file(s)]                                            ";
	help_text[21] = L"+# :go to line #  -i :no info window  -e : don't expand tabs  -h :no highlight";
	control_keys[0] = L"^[ (escape) menu  ^e search prompt  ^y delete line    ^u up     ^p prev page  ";
	control_keys[1] = L"^a ascii code     ^x search         ^z undelete line  ^d down   ^n next page  ";
	control_keys[2] = L"^b bottom of text ^g begin of line  ^w delete word    ^l left                 ";
	control_keys[3] = L"^t top of text    ^o end of line    ^v undelete word  ^r right                ";
	control_keys[4] = L"^c command        ^k delete char    ^f undelete char                          ";
	command_strings[0] = L"help : get help info  |file  : print file name         |line : print line # ";
	command_strings[1] = L"read : (disabled)     |char  : ascii code of char      |0-9 : go to line \"#\"";
	command_strings[2] = L"save: save changes    |case  : case sensitive search   |exit : leave and save ";
	command_strings[3] = L"!cmd : (disabled)     |nocase: ignore case in search   |quit : leave, no save";
	command_strings[4] = L"expand: expand tabs   |noexpand: do not expand tabs                           ";
	com_win_message = L"    press Escape (^[) for menu";
	no_file_string = "no file";
	ascii_code_str = L"ascii code: ";
	command_str = L"command: ";
	char_str = "character = %d";
	unkn_cmd_str = "unknown command \"%S\"";
	non_unique_cmd_msg = L"entered command is not unique";
	line_num_str = "line %d  ";
	line_len_str = "length = %d";
	current_file_str = "current file is \"%S\" ";
	usage0 = L"usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n";
	usage1 = L"       -i   turn off info window\n";
	usage2 = L"       -e   do not convert tabs to spaces\n";
	usage3 = L"       -h   do not use highlighting\n";
	file_is_dir_msg = "file \"%s\" is a directory";
	new_file_msg = "new file \"%s\"";
	cant_open_msg = "can't open \"%s\"";
	open_file_msg = L"file \"%s\", %d lines";
	file_read_fin_msg = "finished reading file \"%s\"";
	reading_file_msg = "reading file \"%s\"";
	read_only_msg = ", read only";
	file_read_lines_msg = "file \"%s\", %d lines";
	save_file_name_prompt = L"enter name of file: ";
	file_not_saved_msg = "no filename entered: file not saved";
	changes_made_prompt = L"changes have been made, are you sure? (y/n [n]) ";
	yes_char = L"y";
	file_exists_prompt = L"file already exists, overwrite? (y/n) [n] ";
	create_file_fail_msg = "unable to create file \"%s\"";
	writing_file_msg = "writing file \"%s\"";
	file_written_msg = "\"%s\" %d lines, %d characters";
	searching_msg = "           ...searching";
	str_not_found_msg = "string \"%S\" not found";
	search_prompt_str = L"search for: ";
	continue_msg = L"press return to continue ";
	menu_cancel_msg = L"press Esc to cancel";
	menu_size_err_msg = L"menu too large for window";
	press_any_key_msg = L"press any key to continue ";
	ON = L"ON";
	OFF = L"OFF";
	HELP = L"HELP";
	SAVE = L"SAVE";
	READ = L"READ";
	LINE = L"LINE";
	FILE_str = L"FILE";
	CHARACTER = L"CHARACTER";
	REDRAW = L"REDRAW";
	RESEQUENCE = L"RESEQUENCE";
	AUTHOR = L"AUTHOR";
	ee_VERSION = L"VERSION";
	CASE = L"CASE";
	NOCASE = L"NOCASE";
	EXPAND = L"EXPAND";
	NOEXPAND = L"NOEXPAND";
	Exit_string = L"EXIT";
	QUIT_string = L"QUIT";
	INFO = L"INFO";
	NOINFO = L"NOINFO";
	MARGINS = L"MARGINS";
	NOMARGINS = L"NOMARGINS";
	AUTOFORMAT = L"AUTOFORMAT";
	NOAUTOFORMAT = L"NOAUTOFORMAT";
	Echo = L"ECHO";
	PRINTCOMMAND = L"PRINTCOMMAND";
	RIGHTMARGIN = L"RIGHTMARGIN";
	HIGHLIGHT = L"HIGHLIGHT";
	NOHIGHLIGHT = L"NOHIGHLIGHT";
	EIGHTBIT = L"EIGHTBIT";
	NOEIGHTBIT = L"NOEIGHTBIT";
	/*
	 |	additions
	 */
	emacs_help_text[0] = help_text[0];
	emacs_help_text[1] = L"^a beginning of line    ^i tab                  ^r restore word            ";
	emacs_help_text[2] = L"^b back 1 char          ^j undel char           ^t top of text             ";
	emacs_help_text[3] = L"^c command              ^k delete line          ^u bottom of text          ";
	emacs_help_text[4] = L"^d delete char          ^l undelete line        ^v next page               ";
	emacs_help_text[5] = L"^e end of line          ^m newline              ^w delete word             ";
	emacs_help_text[6] = L"^f forward 1 char       ^n next line            ^x search                  ";
	emacs_help_text[7] = L"^g go back 1 page       ^o ascii char insert    ^y search prompt           ";
	emacs_help_text[8] = L"^h backspace            ^p prev line            ^z next word               ";
	emacs_help_text[9] = help_text[9];
	emacs_help_text[10] = help_text[10];
	emacs_help_text[11] = help_text[11];
	emacs_help_text[12] = help_text[12];
	emacs_help_text[13] = help_text[13];
	emacs_help_text[14] = help_text[14];
	emacs_help_text[15] = help_text[15];
	emacs_help_text[16] = help_text[16];
	emacs_help_text[17] = help_text[17];
	emacs_help_text[18] = help_text[18];
	emacs_help_text[19] = help_text[19];
	emacs_help_text[20] = help_text[20];
	emacs_help_text[21] = help_text[21];
	emacs_control_keys[0] = L"^[ (escape) menu  ^y search prompt  ^k delete line   ^p prev li   ^g prev page";
	emacs_control_keys[1] = L"^o ascii code     ^x search         ^l undelete line ^n next li   ^v next page";
	emacs_control_keys[2] = L"^u end of file    ^a begin of line  ^w delete word   ^b back 1 char           ";
	emacs_control_keys[3] = L"^t top of text    ^e end of line    ^r restore word  ^f forward 1 char        ";
	emacs_control_keys[4] = L"^c command        ^d delete char    ^j undelete char ^z next word              ";
	EMACS_string = L"EMACS";
	NOEMACS_string = L"NOEMACS";
	usage4 = L"       +#   put cursor at line #\n";
	menu_too_lrg_msg = "menu too large for window";
	more_above_str = L"^^more^^";
	more_below_str = L"VVmoreVV";
	

	commands[0] = HELP;
	commands[1] = SAVE;
	commands[2] = READ;
	commands[3] = LINE;
	commands[4] = FILE_str;
	commands[5] = REDRAW;
	commands[6] = RESEQUENCE;
	commands[7] = AUTHOR;
	commands[8] = ee_VERSION;
	commands[9] = CASE;
	commands[10] = NOCASE;
	commands[11] = EXPAND;
	commands[12] = NOEXPAND;
	commands[13] = Exit_string;
	commands[14] = QUIT_string;
	commands[15] = L"<";
	commands[16] = L">";
	commands[17] = L"!";
	commands[18] = L"0";
	commands[19] = L"1";
	commands[20] = L"2";
	commands[21] = L"3";
	commands[22] = L"4";
	commands[23] = L"5";
	commands[24] = L"6";
	commands[25] = L"7";
	commands[26] = L"8";
	commands[27] = L"9";
	commands[28] = CHARACTER;
	commands[29] = NULL;
}