1/*
2 |	ee (easy editor)
3 |
4 |	An easy to use, simple screen oriented editor.
5 |
6 |	written by Hugh Mahon
7 |
8 |
9 |      Copyright (c) 2009, Hugh Mahon
10 |      All rights reserved.
11 |
12 |      Redistribution and use in source and binary forms, with or without
13 |      modification, are permitted provided that the following conditions
14 |      are met:
15 |
16 |          * Redistributions of source code must retain the above copyright
17 |            notice, this list of conditions and the following disclaimer.
18 |          * Redistributions in binary form must reproduce the above
19 |            copyright notice, this list of conditions and the following
20 |            disclaimer in the documentation and/or other materials provided
21 |            with the distribution.
22 |
23 |      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 |      "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 |      LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 |      FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 |      COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 |      INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 |      BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 |      LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 |      CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 |      LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 |      ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 |      POSSIBILITY OF SUCH DAMAGE.
35 |
36 |     -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
37 |
38 |	This editor was purposely developed to be simple, both in
39 |	interface and implementation.  This editor was developed to
40 |	address a specific audience: the user who is new to computers
41 |	(especially UNIX).
42 |
43 |	ee is not aimed at technical users; for that reason more
44 |	complex features were intentionally left out.  In addition,
45 |	ee is intended to be compiled by people with little computer
46 |	experience, which means that it needs to be small, relatively
47 |	simple in implementation, and portable.
48 |
49 |	This software and documentation contains
50 |	proprietary information which is protected by
51 |	copyright.  All rights are reserved.
52 |
53 |	$Header: /home/hugh/sources/old_ae/RCS/ee.c,v 1.104 2010/06/04 01:55:31 hugh Exp hugh $
54 |
55 */
56
57char *ee_copyright_message =
58"Copyright (c) 1986, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 2009 Hugh Mahon ";
59
60#include "ee_version.h"
61
62char *version = "@(#) ee, version "  EE_VERSION  " $Revision: 1.104 $";
63
64#ifdef NCURSE
65#include "new_curse.h"
66#elif HAS_NCURSES
67#include <ncurses.h>
68#else
69#include <curses.h>
70#endif
71
72#include <ctype.h>
73#include <signal.h>
74#include <fcntl.h>
75#include <sys/types.h>
76#include <sys/stat.h>
77#include <errno.h>
78#include <string.h>
79#include <pwd.h>
80#include <locale.h>
81
82#ifdef HAS_SYS_WAIT
83#include <sys/wait.h>
84#endif
85
86#ifdef HAS_STDLIB
87#include <stdlib.h>
88#endif
89
90#ifdef HAS_STDARG
91#include <stdarg.h>
92#endif
93
94#ifdef HAS_UNISTD
95#include <unistd.h>
96#endif
97
98#ifndef NO_CATGETS
99#include <nl_types.h>
100
101nl_catd catalog;
102#else
103#define catgetlocal(a, b) (b)
104#endif /* NO_CATGETS */
105
106#ifndef SIGCHLD
107#define SIGCHLD SIGCLD
108#endif
109
110#define TAB 9
111#define max(a, b)	(a > b ? a : b)
112#define min(a, b)	(a < b ? a : b)
113
114/*
115 |	defines for type of data to show in info window
116 */
117
118#define CONTROL_KEYS 1
119#define COMMANDS     2
120
121struct text {
122	unsigned char *line;		/* line of characters		*/
123	int line_number;		/* line number			*/
124	int line_length;	/* actual number of characters in the line */
125	int max_length;	/* maximum number of characters the line handles */
126	struct text *next_line;		/* next line of text		*/
127	struct text *prev_line;		/* previous line of text	*/
128	};
129
130struct text *first_line;	/* first line of current buffer		*/
131struct text *dlt_line;		/* structure for info on deleted line	*/
132struct text *curr_line;		/* current line cursor is on		*/
133struct text *tmp_line;		/* temporary line pointer		*/
134struct text *srch_line;		/* temporary pointer for search routine */
135
136struct files {		/* structure to store names of files to be edited*/
137	unsigned char *name;		/* name of file				*/
138	struct files *next_name;
139	};
140
141struct files *top_of_stack = NULL;
142
143int d_wrd_len;			/* length of deleted word		*/
144int position;			/* offset in bytes from begin of line	*/
145int scr_pos;			/* horizontal position			*/
146int scr_vert;			/* vertical position on screen		*/
147int scr_horz;			/* horizontal position on screen	*/
148int absolute_lin;		/* number of lines from top		*/
149int tmp_vert, tmp_horz;
150int input_file;			/* indicate to read input file		*/
151int recv_file;			/* indicate reading a file		*/
152int edit;			/* continue executing while true	*/
153int gold;			/* 'gold' function key pressed		*/
154int fildes;			/* file descriptor			*/
155int case_sen;			/* case sensitive search flag		*/
156int last_line;			/* last line for text display		*/
157int last_col;			/* last column for text display		*/
158int horiz_offset = 0;		/* offset from left edge of text	*/
159int clear_com_win;		/* flag to indicate com_win needs clearing */
160int text_changes = FALSE;	/* indicate changes have been made to text */
161int get_fd;			/* file descriptor for reading a file	*/
162int info_window = TRUE;		/* flag to indicate if help window visible */
163int info_type = CONTROL_KEYS;	/* flag to indicate type of info to display */
164int expand_tabs = TRUE;		/* flag for expanding tabs		*/
165int right_margin = 0;		/* the right margin 			*/
166int observ_margins = TRUE;	/* flag for whether margins are observed */
167int shell_fork;
168int temp_stdin;			/* temporary storage for stdin		*/
169int temp_stdout;		/* temp storage for stdout descriptor	*/
170int temp_stderr;		/* temp storage for stderr descriptor	*/
171int pipe_out[2];		/* pipe file desc for output		*/
172int pipe_in[2];			/* pipe file descriptors for input	*/
173int out_pipe;			/* flag that info is piped out		*/
174int in_pipe;			/* flag that info is piped in		*/
175int formatted = FALSE;		/* flag indicating paragraph formatted	*/
176int auto_format = FALSE;	/* flag for auto_format mode		*/
177int restricted = FALSE;		/* flag to indicate restricted mode	*/
178int nohighlight = FALSE;	/* turns off highlighting		*/
179int eightbit = TRUE;		/* eight bit character flag		*/
180int local_LINES = 0;		/* copy of LINES, to detect when win resizes */
181int local_COLS = 0;		/* copy of COLS, to detect when win resizes  */
182int curses_initialized = FALSE;	/* flag indicating if curses has been started*/
183int emacs_keys_mode = FALSE;	/* mode for if emacs key binings are used    */
184int ee_chinese = FALSE;		/* allows handling of multi-byte characters  */
185				/* by checking for high bit in a byte the    */
186				/* code recognizes a two-byte character      */
187				/* sequence				     */
188
189unsigned char *point;		/* points to current position in line	*/
190unsigned char *srch_str;	/* pointer for search string		*/
191unsigned char *u_srch_str;	/* pointer to non-case sensitive search	*/
192unsigned char *srch_1;		/* pointer to start of suspect string	*/
193unsigned char *srch_2;		/* pointer to next character of string	*/
194unsigned char *srch_3;
195unsigned char *in_file_name = NULL;	/* name of input file		*/
196char *tmp_file;	/* temporary file name			*/
197unsigned char *d_char;		/* deleted character			*/
198unsigned char *d_word;		/* deleted word				*/
199unsigned char *d_line;		/* deleted line				*/
200char in_string[513];	/* buffer for reading a file		*/
201unsigned char *print_command = (unsigned char *)"lpr";	/* string to use for the print command 	*/
202unsigned char *start_at_line = NULL;	/* move to this line at start of session*/
203int in;				/* input character			*/
204
205FILE *temp_fp;			/* temporary file pointer		*/
206FILE *bit_bucket;		/* file pointer to /dev/null		*/
207
208char *table[] = {
209	"^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "\t", "^J",
210	"^K", "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U",
211	"^V", "^W", "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_"
212	};
213
214WINDOW *com_win;
215WINDOW *text_win;
216WINDOW *help_win;
217WINDOW *info_win;
218
219
220/*
221 |	The following structure allows menu items to be flexibly declared.
222 |	The first item is the string describing the selection, the second
223 |	is the address of the procedure to call when the item is selected,
224 |	and the third is the argument for the procedure.
225 |
226 |	For those systems with i18n, the string should be accompanied by a
227 |	catalog number.  The 'int *' should be replaced with 'void *' on
228 |	systems with that type.
229 |
230 |	The first menu item will be the title of the menu, with NULL
231 |	parameters for the procedure and argument, followed by the menu items.
232 |
233 |	If the procedure value is NULL, the menu item is displayed, but no
234 |	procedure is called when the item is selected.  The number of the
235 |	item will be returned.  If the third (argument) parameter is -1, no
236 |	argument is given to the procedure when it is called.
237 */
238
239struct menu_entries {
240	char *item_string;
241	int (*procedure)(struct menu_entries *);
242	struct menu_entries *ptr_argument;
243	int (*iprocedure)(int);
244	void (*nprocedure)(void);
245	int argument;
246	};
247
248unsigned char *resiz_line(int factor, struct text *rline, int rpos);
249void insert(int character);
250void delete(int disp);
251void scanline(unsigned char *pos);
252int tabshift(int temp_int);
253int out_char(WINDOW *window, int character, int column);
254int len_char(int character, int column);
255void draw_line(int vertical, int horiz, unsigned char *ptr, int t_pos, int length);
256void insert_line(int disp);
257struct text *txtalloc(void);
258struct files *name_alloc(void);
259unsigned char *next_word(unsigned char *string);
260void prev_word(void);
261void control(void);
262void emacs_control(void);
263void bottom(void);
264void top(void);
265void nextline(void);
266void prevline(void);
267void left(int disp);
268void right(int disp);
269void find_pos(void);
270void up(void);
271void down(void);
272void function_key(void);
273void print_buffer(void);
274void command_prompt(void);
275void command(char *cmd_str1);
276int scan(char *line, int offset, int column);
277char *get_string(char *prompt, int advance);
278int compare(char *string1, char *string2, int sensitive);
279void goto_line(char *cmd_str);
280void midscreen(int line, unsigned char *pnt);
281void get_options(int numargs, char *arguments[]);
282void check_fp(void);
283void get_file(char *file_name);
284void get_line(int length, unsigned char *in_string, int *append);
285void draw_screen(void);
286void finish(void);
287int quit(int noverify);
288void edit_abort(int arg);
289void delete_text(void);
290int write_file(char *file_name, int warn_if_exists);
291int search(int display_message);
292void search_prompt(void);
293void del_char(void);
294void undel_char(void);
295void del_word(void);
296void undel_word(void);
297void del_line(void);
298void undel_line(void);
299void adv_word(void);
300void move_rel(int direction, int lines);
301void eol(void);
302void bol(void);
303void adv_line(void);
304void sh_command(char *string);
305void set_up_term(void);
306void resize_check(void);
307int menu_op(struct menu_entries *);
308void 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);
309void help(void);
310void paint_info_win(void);
311void no_info_window(void);
312void create_info_window(void);
313int file_op(int arg);
314void shell_op(void);
315void leave_op(void);
316void redraw(void);
317int Blank_Line(struct text *test_line);
318void Format(void);
319void ee_init(void);
320void dump_ee_conf(void);
321void echo_string(char *string);
322void spell_op(void);
323void ispell_op(void);
324int first_word_len(struct text *test_line);
325void Auto_Format(void);
326void modes_op(void);
327char *is_in_string(char *string, char *substring);
328char *resolve_name(char *name);
329int restrict_mode(void);
330int unique_test(char *string, char *list[]);
331void strings_init(void);
332
333#undef P_
334/*
335 |	allocate space here for the strings that will be in the menu
336 */
337
338struct menu_entries modes_menu[] = {
339	{"", NULL, NULL, NULL, NULL, 0}, 	/* title		*/
340	{"", NULL, NULL, NULL, NULL, -1}, 	/* 1. tabs to spaces	*/
341	{"", NULL, NULL, NULL, NULL, -1}, 	/* 2. case sensitive search*/
342	{"", NULL, NULL, NULL, NULL, -1}, 	/* 3. margins observed	*/
343	{"", NULL, NULL, NULL, NULL, -1}, 	/* 4. auto-paragraph	*/
344	{"", NULL, NULL, NULL, NULL, -1}, 	/* 5. eightbit characters*/
345	{"", NULL, NULL, NULL, NULL, -1}, 	/* 6. info window	*/
346	{"", NULL, NULL, NULL, NULL, -1}, 	/* 7. emacs key bindings*/
347	{"", NULL, NULL, NULL, NULL, -1}, 	/* 8. right margin	*/
348	{"", NULL, NULL, NULL, NULL, -1}, 	/* 9. chinese text	*/
349	{"", NULL, NULL, NULL, dump_ee_conf, -1}, /* 10. save editor config */
350	{NULL, NULL, NULL, NULL, NULL, -1}	/* terminator		*/
351	};
352
353char *mode_strings[11];
354
355#define NUM_MODES_ITEMS 10
356
357struct menu_entries config_dump_menu[] = {
358	{"", NULL, NULL, NULL, NULL, 0},
359	{"", NULL, NULL, NULL, NULL, -1},
360	{"", NULL, NULL, NULL, NULL, -1},
361	{NULL, NULL, NULL, NULL, NULL, -1}
362	};
363
364struct menu_entries leave_menu[] = {
365	{"", NULL, NULL, NULL, NULL, -1},
366	{"", NULL, NULL, NULL, finish, -1},
367	{"", NULL, NULL, quit, NULL, TRUE},
368	{NULL, NULL, NULL, NULL, NULL, -1}
369	};
370
371#define READ_FILE 1
372#define WRITE_FILE 2
373#define SAVE_FILE 3
374
375struct menu_entries file_menu[] = {
376	{"", NULL, NULL, NULL, NULL, -1},
377	{"", NULL, NULL, file_op, NULL, READ_FILE},
378	{"", NULL, NULL, file_op, NULL, WRITE_FILE},
379	{"", NULL, NULL, file_op, NULL, SAVE_FILE},
380	{"", NULL, NULL, NULL, print_buffer, -1},
381	{NULL, NULL, NULL, NULL, NULL, -1}
382	};
383
384struct menu_entries search_menu[] = {
385	{"", NULL, NULL, NULL, NULL, 0},
386	{"", NULL, NULL, NULL, search_prompt, -1},
387	{"", NULL, NULL, search, NULL, TRUE},
388	{NULL, NULL, NULL, NULL, NULL, -1}
389	};
390
391struct menu_entries spell_menu[] = {
392	{"", NULL, NULL, NULL, NULL, -1},
393	{"", NULL, NULL, NULL, spell_op, -1},
394	{"", NULL, NULL, NULL, ispell_op, -1},
395	{NULL, NULL, NULL, NULL, NULL, -1}
396	};
397
398struct menu_entries misc_menu[] = {
399	{"", NULL, NULL, NULL, NULL, -1},
400	{"", NULL, NULL, NULL, Format, -1},
401	{"", NULL, NULL, NULL, shell_op, -1},
402	{"", menu_op, spell_menu, NULL, NULL, -1},
403	{NULL, NULL, NULL, NULL, NULL, -1}
404	};
405
406struct menu_entries main_menu[] = {
407	{"", NULL, NULL, NULL, NULL, -1},
408	{"", NULL, NULL, NULL, leave_op, -1},
409	{"", NULL, NULL, NULL, help, -1},
410	{"", menu_op, file_menu, NULL, NULL, -1},
411	{"", NULL, NULL, NULL, redraw, -1},
412	{"", NULL, NULL, NULL, modes_op, -1},
413	{"", menu_op, search_menu, NULL, NULL, -1},
414	{"", menu_op, misc_menu, NULL, NULL, -1},
415	{NULL, NULL, NULL, NULL, NULL, -1}
416	};
417
418char *help_text[23];
419char *control_keys[5];
420
421char *emacs_help_text[22];
422char *emacs_control_keys[5];
423
424char *command_strings[5];
425char *commands[32];
426char *init_strings[22];
427
428#define MENU_WARN 1
429
430#define max_alpha_char 36
431
432/*
433 |	Declarations for strings for localization
434 */
435
436char *com_win_message;		/* to be shown in com_win if no info window */
437char *no_file_string;
438char *ascii_code_str;
439char *printer_msg_str;
440char *command_str;
441char *file_write_prompt_str;
442char *file_read_prompt_str;
443char *char_str;
444char *unkn_cmd_str;
445char *non_unique_cmd_msg;
446char *line_num_str;
447char *line_len_str;
448char *current_file_str;
449char *usage0;
450char *usage1;
451char *usage2;
452char *usage3;
453char *usage4;
454char *file_is_dir_msg;
455char *new_file_msg;
456char *cant_open_msg;
457char *open_file_msg;
458char *file_read_fin_msg;
459char *reading_file_msg;
460char *read_only_msg;
461char *file_read_lines_msg;
462char *save_file_name_prompt;
463char *file_not_saved_msg;
464char *changes_made_prompt;
465char *yes_char;
466char *file_exists_prompt;
467char *create_file_fail_msg;
468char *writing_file_msg;
469char *file_written_msg;
470char *searching_msg;
471char *str_not_found_msg;
472char *search_prompt_str;
473char *exec_err_msg;
474char *continue_msg;
475char *menu_cancel_msg;
476char *menu_size_err_msg;
477char *press_any_key_msg;
478char *shell_prompt;
479char *formatting_msg;
480char *shell_echo_msg;
481char *spell_in_prog_msg;
482char *margin_prompt;
483char *restricted_msg;
484char *ON;
485char *OFF;
486char *HELP;
487char *WRITE;
488char *READ;
489char *LINE;
490char *FILE_str;
491char *CHARACTER;
492char *REDRAW;
493char *RESEQUENCE;
494char *AUTHOR;
495char *VERSION;
496char *CASE;
497char *NOCASE;
498char *EXPAND;
499char *NOEXPAND;
500char *Exit_string;
501char *QUIT_string;
502char *INFO;
503char *NOINFO;
504char *MARGINS;
505char *NOMARGINS;
506char *AUTOFORMAT;
507char *NOAUTOFORMAT;
508char *Echo;
509char *PRINTCOMMAND;
510char *RIGHTMARGIN;
511char *HIGHLIGHT;
512char *NOHIGHLIGHT;
513char *EIGHTBIT;
514char *NOEIGHTBIT;
515char *EMACS_string;
516char *NOEMACS_string;
517char *conf_dump_err_msg;
518char *conf_dump_success_msg;
519char *conf_not_saved_msg;
520char *ree_no_file_msg;
521char *cancel_string;
522char *menu_too_lrg_msg;
523char *more_above_str, *more_below_str;
524char *separator = "===============================================================================";
525
526char *chinese_cmd, *nochinese_cmd;
527
528#ifndef __STDC__
529#ifndef HAS_STDLIB
530extern char *malloc();
531extern char *realloc();
532extern char *getenv();
533FILE *fopen();			/* declaration for open function	*/
534#endif /* HAS_STDLIB */
535#endif /* __STDC__ */
536
537/* beginning of main program		*/
538int
539main(int argc, char *argv[])
540{
541	int counter;
542
543	for (counter = 1; counter < 24; counter++)
544		signal(counter, SIG_IGN);
545
546	/* Always read from (and write to) a terminal. */
547	if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {
548		fprintf(stderr,
549		    "ee's standard input and output must be a terminal\n");
550		exit(1);
551	}
552
553	signal(SIGCHLD, SIG_DFL);
554	signal(SIGSEGV, SIG_DFL);
555	signal(SIGINT, edit_abort);
556	d_char = malloc(3);	/* provide a buffer for multi-byte chars */
557	d_word = malloc(150);
558	*d_word = '\0';
559	d_line = NULL;
560	dlt_line = txtalloc();
561	dlt_line->line = d_line;
562	dlt_line->line_length = 0;
563	curr_line = first_line = txtalloc();
564	curr_line->line = point = malloc(10);
565	curr_line->line_length = 1;
566	curr_line->max_length = 10;
567	curr_line->prev_line = NULL;
568	curr_line->next_line = NULL;
569	curr_line->line_number  = 1;
570	srch_str = NULL;
571	u_srch_str = NULL;
572	position = 1;
573	scr_pos =0;
574	scr_vert = 0;
575	scr_horz = 0;
576	absolute_lin = 1;
577	bit_bucket = fopen("/dev/null", "w");
578	edit = TRUE;
579	gold = case_sen = FALSE;
580	shell_fork = TRUE;
581	strings_init();
582	ee_init();
583	if (argc > 0 )
584		get_options(argc, argv);
585	set_up_term();
586	if (right_margin == 0)
587		right_margin = COLS - 1;
588	if (top_of_stack == NULL)
589	{
590		if (restrict_mode())
591		{
592			wmove(com_win, 0, 0);
593			werase(com_win);
594			wprintw(com_win, ree_no_file_msg);
595			wrefresh(com_win);
596			edit_abort(0);
597		}
598		wprintw(com_win, no_file_string);
599		wrefresh(com_win);
600	}
601	else
602		check_fp();
603
604	clear_com_win = TRUE;
605
606	counter = 0;
607
608	while(edit)
609	{
610		/*
611		 |  display line and column information
612		 */
613		if (info_window)
614		{
615			if (!nohighlight)
616				wstandout(info_win);
617			wmove(info_win, 5, 0);
618			wprintw(info_win, separator);
619			wmove(info_win, 5, 5);
620			wprintw(info_win, "line %d col %d lines from top %d ",
621			          curr_line->line_number, scr_horz, absolute_lin);
622			wstandend(info_win);
623			wrefresh(info_win);
624		}
625
626		wrefresh(text_win);
627		in = wgetch(text_win);
628		if (in == -1)
629			exit(0);  /* without this exit ee will go into an
630			             infinite loop if the network
631			             session detaches */
632
633		resize_check();
634
635		if (clear_com_win)
636		{
637			clear_com_win = FALSE;
638			wmove(com_win, 0, 0);
639			werase(com_win);
640			if (!info_window)
641			{
642				wprintw(com_win, "%s", com_win_message);
643			}
644			wrefresh(com_win);
645		}
646
647		if (in > 255)
648			function_key();
649		else if ((in == '\10') || (in == 127))
650		{
651			in = 8;		/* make sure key is set to backspace */
652			delete(TRUE);
653		}
654		else if ((in > 31) || (in == 9))
655			insert(in);
656		else if ((in >= 0) && (in <= 31))
657		{
658			if (emacs_keys_mode)
659				emacs_control();
660			else
661				control();
662		}
663	}
664	return(0);
665}
666
667/* resize the line to length + factor*/
668unsigned char *
669resiz_line(int factor, struct text *rline, int rpos)
670{
671	unsigned char *rpoint;
672	int resiz_var;
673
674	rline->max_length += factor;
675	rpoint = rline->line = realloc(rline->line, rline->max_length );
676	for (resiz_var = 1 ; (resiz_var < rpos) ; resiz_var++)
677		rpoint++;
678	return(rpoint);
679}
680
681/* insert character into line		*/
682void
683insert(int character)
684{
685	int counter;
686	int value;
687	unsigned char *temp;	/* temporary pointer			*/
688	unsigned char *temp2;	/* temporary pointer			*/
689
690	if ((character == '\011') && (expand_tabs))
691	{
692		counter = len_char('\011', scr_horz);
693		for (; counter > 0; counter--)
694			insert(' ');
695		if (auto_format)
696			Auto_Format();
697		return;
698	}
699	text_changes = TRUE;
700	if ((curr_line->max_length - curr_line->line_length) < 5)
701		point = resiz_line(10, curr_line, position);
702	curr_line->line_length++;
703	temp = point;
704	counter = position;
705	while (counter < curr_line->line_length)	/* find end of line */
706	{
707		counter++;
708		temp++;
709	}
710	temp++;			/* increase length of line by one	*/
711	while (point < temp)
712	{
713		temp2=temp - 1;
714		*temp= *temp2;	/* shift characters over by one		*/
715		temp--;
716	}
717	*point = character;	/* insert new character			*/
718	wclrtoeol(text_win);
719	if (!isprint((unsigned char)character)) /* check for TAB character*/
720	{
721		scr_pos = scr_horz += out_char(text_win, character, scr_horz);
722		point++;
723		position++;
724	}
725	else
726	{
727		waddch(text_win, (unsigned char)character);
728		scr_pos = ++scr_horz;
729		point++;
730		position ++;
731	}
732
733	if ((observ_margins) && (right_margin < scr_pos))
734	{
735		counter = position;
736		while (scr_pos > right_margin)
737			prev_word();
738		if (scr_pos == 0)
739		{
740			while (position < counter)
741				right(TRUE);
742		}
743		else
744		{
745			counter -= position;
746			insert_line(TRUE);
747			for (value = 0; value < counter; value++)
748				right(TRUE);
749		}
750	}
751
752	if ((scr_horz - horiz_offset) > last_col)
753	{
754		horiz_offset += 8;
755		midscreen(scr_vert, point);
756	}
757
758	if ((auto_format) && (character == ' ') && (!formatted))
759		Auto_Format();
760	else if ((character != ' ') && (character != '\t'))
761		formatted = FALSE;
762
763	draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
764}
765
766/* delete character		*/
767void
768delete(int disp)
769{
770	unsigned char *tp;
771	unsigned char *temp2;
772	struct text *temp_buff;
773	int temp_vert;
774	int temp_pos;
775	int del_width = 1;
776
777	if (point != curr_line->line)	/* if not at beginning of line	*/
778	{
779		text_changes = TRUE;
780		temp2 = tp = point;
781		if ((ee_chinese) && (position >= 2) && (*(point - 2) > 127))
782		{
783			del_width = 2;
784		}
785		tp -= del_width;
786		point -= del_width;
787		position -= del_width;
788		temp_pos = position;
789		curr_line->line_length -= del_width;
790		if ((*tp < ' ') || (*tp >= 127))	/* check for TAB */
791			scanline(tp);
792		else
793			scr_horz -= del_width;
794		scr_pos = scr_horz;
795		if (in == 8)
796		{
797			if (del_width == 1)
798				*d_char = *point; /* save deleted character  */
799			else
800			{
801				d_char[0] = *point;
802				d_char[1] = *(point + 1);
803			}
804			d_char[del_width] = '\0';
805		}
806		while (temp_pos <= curr_line->line_length)
807		{
808			temp_pos++;
809			*tp = *temp2;
810			tp++;
811			temp2++;
812		}
813		if ((scr_horz < horiz_offset) && (horiz_offset > 0))
814		{
815			horiz_offset -= 8;
816			midscreen(scr_vert, point);
817		}
818	}
819	else if (curr_line->prev_line != NULL)
820	{
821		text_changes = TRUE;
822		left(disp);			/* go to previous line	*/
823		temp_buff = curr_line->next_line;
824		point = resiz_line(temp_buff->line_length, curr_line, position);
825		if (temp_buff->next_line != NULL)
826			temp_buff->next_line->prev_line = curr_line;
827		curr_line->next_line = temp_buff->next_line;
828		temp2 = temp_buff->line;
829		if (in == 8)
830		{
831			d_char[0] = '\n';
832			d_char[1] = '\0';
833		}
834		tp = point;
835		temp_pos = 1;
836		while (temp_pos < temp_buff->line_length)
837		{
838			curr_line->line_length++;
839			temp_pos++;
840			*tp = *temp2;
841			tp++;
842			temp2++;
843		}
844		*tp = '\0';
845		free(temp_buff->line);
846		free(temp_buff);
847		temp_buff = curr_line;
848		temp_vert = scr_vert;
849		scr_pos = scr_horz;
850		if (scr_vert < last_line)
851		{
852			wmove(text_win, scr_vert + 1, 0);
853			wdeleteln(text_win);
854		}
855		while ((temp_buff != NULL) && (temp_vert < last_line))
856		{
857			temp_buff = temp_buff->next_line;
858			temp_vert++;
859		}
860		if ((temp_vert == last_line) && (temp_buff != NULL))
861		{
862			tp = temp_buff->line;
863			wmove(text_win, last_line,0);
864			wclrtobot(text_win);
865			draw_line(last_line, 0, tp, 1, temp_buff->line_length);
866			wmove(text_win, scr_vert, (scr_horz - horiz_offset));
867		}
868	}
869	draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
870	formatted = FALSE;
871}
872
873/* find the proper horizontal position for the pointer	*/
874void
875scanline(unsigned char *pos)
876{
877	int temp;
878	unsigned char *ptr;
879
880	ptr = curr_line->line;
881	temp = 0;
882	while (ptr < pos)
883	{
884		if (*ptr <= 8)
885			temp += 2;
886		else if (*ptr == 9)
887			temp += tabshift(temp);
888		else if ((*ptr >= 10) && (*ptr <= 31))
889			temp += 2;
890		else if ((*ptr >= 32) && (*ptr < 127))
891			temp++;
892		else if (*ptr == 127)
893			temp += 2;
894		else if (!eightbit)
895			temp += 5;
896		else
897			temp++;
898		ptr++;
899	}
900	scr_horz = temp;
901	if ((scr_horz - horiz_offset) > last_col)
902	{
903		horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
904		midscreen(scr_vert, point);
905	}
906	else if (scr_horz < horiz_offset)
907	{
908		horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
909		midscreen(scr_vert, point);
910	}
911}
912
913/* give the number of spaces to shift	*/
914int
915tabshift(int temp_int)
916{
917	int leftover;
918
919	leftover = ((temp_int + 1) % 8);
920	if (leftover == 0)
921		return (1);
922	else
923		return (9 - leftover);
924}
925
926/* output non-printing character */
927int
928out_char(WINDOW *window, int character, int column)
929{
930	int i1, i2;
931	char *string;
932	char string2[8];
933
934	if (character == TAB)
935	{
936		i1 = tabshift(column);
937		for (i2 = 0;
938		  (i2 < i1) && (((column+i2+1)-horiz_offset) < last_col); i2++)
939		{
940			waddch(window, ' ');
941		}
942		return(i1);
943	}
944	else if ((character >= '\0') && (character < ' '))
945	{
946		string = table[(int) character];
947	}
948	else if ((character < 0) || (character >= 127))
949	{
950		if (character == 127)
951			string = "^?";
952		else if (!eightbit)
953		{
954			sprintf(string2, "<%d>", (character < 0) ? (character + 256) : character);
955			string = string2;
956		}
957		else
958		{
959			waddch(window, (unsigned char)character );
960			return(1);
961		}
962	}
963	else
964	{
965		waddch(window, (unsigned char)character);
966		return(1);
967	}
968	for (i2 = 0; (string[i2] != '\0') && (((column+i2+1)-horiz_offset) < last_col); i2++)
969		waddch(window, (unsigned char)string[i2]);
970	return(strlen(string));
971}
972
973/* return the length of the character	*/
974int
975len_char(int character, int column)
976{
977	int length;
978
979	if (character == '\t')
980		length = tabshift(column);
981	else if ((character >= 0) && (character < 32))
982		length = 2;
983	else if ((character >= 32) && (character <= 126))
984		length = 1;
985	else if (character == 127)
986		length = 2;
987	else if (((character > 126) || (character < 0)) && (!eightbit))
988		length = 5;
989	else
990		length = 1;
991
992	return(length);
993}
994
995/* redraw line from current position */
996void
997draw_line(int vertical, int horiz, unsigned char *ptr, int t_pos, int length)
998{
999	int d;		/* partial length of special or tab char to display  */
1000	unsigned char *temp;	/* temporary pointer to position in line	     */
1001	int abs_column;	/* offset in screen units from begin of line	     */
1002	int column;	/* horizontal position on screen		     */
1003	int row;	/* vertical position on screen			     */
1004	int posit;	/* temporary position indicator within line	     */
1005
1006	abs_column = horiz;
1007	column = horiz - horiz_offset;
1008	row = vertical;
1009	temp = ptr;
1010	d = 0;
1011	posit = t_pos;
1012	if (column < 0)
1013	{
1014		wmove(text_win, row, 0);
1015		wclrtoeol(text_win);
1016	}
1017	while (column < 0)
1018	{
1019		d = len_char(*temp, abs_column);
1020		abs_column += d;
1021		column += d;
1022		posit++;
1023		temp++;
1024	}
1025	wmove(text_win, row, column);
1026	wclrtoeol(text_win);
1027	while ((posit < length) && (column <= last_col))
1028	{
1029		if (!isprint(*temp))
1030		{
1031			column += len_char(*temp, abs_column);
1032			abs_column += out_char(text_win, *temp, abs_column);
1033		}
1034		else
1035		{
1036			abs_column++;
1037			column++;
1038			waddch(text_win, *temp);
1039		}
1040		posit++;
1041		temp++;
1042	}
1043	if (column < last_col)
1044		wclrtoeol(text_win);
1045	wmove(text_win, vertical, (horiz - horiz_offset));
1046}
1047
1048/* insert new line		*/
1049void
1050insert_line(int disp)
1051{
1052	int temp_pos;
1053	int temp_pos2;
1054	unsigned char *temp;
1055	unsigned char *extra;
1056	struct text *temp_nod;
1057
1058	text_changes = TRUE;
1059	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1060	wclrtoeol(text_win);
1061	temp_nod= txtalloc();
1062	temp_nod->line = extra= malloc(10);
1063	temp_nod->line_length = 1;
1064	temp_nod->max_length = 10;
1065	temp_nod->line_number = curr_line->line_number + 1;
1066	temp_nod->next_line = curr_line->next_line;
1067	if (temp_nod->next_line != NULL)
1068		temp_nod->next_line->prev_line = temp_nod;
1069	temp_nod->prev_line = curr_line;
1070	curr_line->next_line = temp_nod;
1071	temp_pos2 = position;
1072	temp = point;
1073	if (temp_pos2 < curr_line->line_length)
1074	{
1075		temp_pos = 1;
1076		while (temp_pos2 < curr_line->line_length)
1077		{
1078			if ((temp_nod->max_length - temp_nod->line_length)< 5)
1079				extra = resiz_line(10, temp_nod, temp_pos);
1080			temp_nod->line_length++;
1081			temp_pos++;
1082			temp_pos2++;
1083			*extra= *temp;
1084			extra++;
1085			temp++;
1086		}
1087		temp=point;
1088		*temp = '\0';
1089		temp = resiz_line((1 - temp_nod->line_length), curr_line, position);
1090		curr_line->line_length = 1 + temp - curr_line->line;
1091	}
1092	curr_line->line_length = position;
1093	absolute_lin++;
1094	curr_line = temp_nod;
1095	*extra = '\0';
1096	position = 1;
1097	point= curr_line->line;
1098	if (disp)
1099	{
1100		if (scr_vert < last_line)
1101		{
1102			scr_vert++;
1103			wclrtoeol(text_win);
1104			wmove(text_win, scr_vert, 0);
1105			winsertln(text_win);
1106		}
1107		else
1108		{
1109			wmove(text_win, 0,0);
1110			wdeleteln(text_win);
1111			wmove(text_win, last_line,0);
1112			wclrtobot(text_win);
1113		}
1114		scr_pos = scr_horz = 0;
1115		if (horiz_offset)
1116		{
1117			horiz_offset = 0;
1118			midscreen(scr_vert, point);
1119		}
1120		draw_line(scr_vert, scr_horz, point, position,
1121			curr_line->line_length);
1122	}
1123}
1124
1125/* allocate space for line structure	*/
1126struct text *
1127txtalloc(void)
1128{
1129	return((struct text *) malloc(sizeof( struct text)));
1130}
1131
1132/* allocate space for file name list node */
1133struct files *
1134name_alloc(void)
1135{
1136	return((struct files *) malloc(sizeof( struct files)));
1137}
1138
1139/* move to next word in string		*/
1140unsigned char *
1141next_word(unsigned char *string)
1142{
1143	while ((*string != '\0') && ((*string != 32) && (*string != 9)))
1144		string++;
1145	while ((*string != '\0') && ((*string == 32) || (*string == 9)))
1146		string++;
1147	return(string);
1148}
1149
1150/* move to start of previous word in text	*/
1151void
1152prev_word(void)
1153{
1154	if (position != 1)
1155	{
1156		if ((position != 1) && ((point[-1] == ' ') || (point[-1] == '\t')))
1157		{	/* if at the start of a word	*/
1158			while ((position != 1) && ((*point != ' ') && (*point != '\t')))
1159				left(TRUE);
1160		}
1161		while ((position != 1) && ((*point == ' ') || (*point == '\t')))
1162			left(TRUE);
1163		while ((position != 1) && ((*point != ' ') && (*point != '\t')))
1164			left(TRUE);
1165		if ((position != 1) && ((*point == ' ') || (*point == '\t')))
1166			right(TRUE);
1167	}
1168	else
1169		left(TRUE);
1170}
1171
1172/* use control for commands		*/
1173void
1174control(void)
1175{
1176	char *string;
1177
1178	if (in == 1)		/* control a	*/
1179	{
1180		string = get_string(ascii_code_str, TRUE);
1181		if (*string != '\0')
1182		{
1183			in = atoi(string);
1184			wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1185			insert(in);
1186		}
1187		free(string);
1188	}
1189	else if (in == 2)	/* control b	*/
1190		bottom();
1191	else if (in == 3)	/* control c	*/
1192	{
1193		command_prompt();
1194	}
1195	else if (in == 4)	/* control d	*/
1196		down();
1197	else if (in == 5)	/* control e	*/
1198		search_prompt();
1199	else if (in == 6)	/* control f	*/
1200		undel_char();
1201	else if (in == 7)	/* control g	*/
1202		bol();
1203	else if (in == 8)	/* control h	*/
1204		delete(TRUE);
1205	else if (in == 9)	/* control i	*/
1206		;
1207	else if (in == 10)	/* control j	*/
1208		insert_line(TRUE);
1209	else if (in == 11)	/* control k	*/
1210		del_char();
1211	else if (in == 12)	/* control l	*/
1212		left(TRUE);
1213	else if (in == 13)	/* control m	*/
1214		insert_line(TRUE);
1215	else if (in == 14)	/* control n	*/
1216		move_rel('d', max(5, (last_line - 5)));
1217	else if (in == 15)	/* control o	*/
1218		eol();
1219	else if (in == 16)	/* control p	*/
1220		move_rel('u', max(5, (last_line - 5)));
1221	else if (in == 17)	/* control q	*/
1222		;
1223	else if (in == 18)	/* control r	*/
1224		right(TRUE);
1225	else if (in == 19)	/* control s	*/
1226		;
1227	else if (in == 20)	/* control t	*/
1228		top();
1229	else if (in == 21)	/* control u	*/
1230		up();
1231	else if (in == 22)	/* control v	*/
1232		undel_word();
1233	else if (in == 23)	/* control w	*/
1234		del_word();
1235	else if (in == 24)	/* control x	*/
1236		search(TRUE);
1237	else if (in == 25)	/* control y	*/
1238		del_line();
1239	else if (in == 26)	/* control z	*/
1240		undel_line();
1241	else if (in == 27)	/* control [ (escape)	*/
1242	{
1243		menu_op(main_menu);
1244	}
1245}
1246
1247/*
1248 |	Emacs control-key bindings
1249 */
1250
1251void
1252emacs_control(void)
1253{
1254	char *string;
1255
1256	if (in == 1)		/* control a	*/
1257		bol();
1258	else if (in == 2)	/* control b	*/
1259		left(TRUE);
1260	else if (in == 3)	/* control c	*/
1261	{
1262		command_prompt();
1263	}
1264	else if (in == 4)	/* control d	*/
1265		del_char();
1266	else if (in == 5)	/* control e	*/
1267		eol();
1268	else if (in == 6)	/* control f	*/
1269		right(TRUE);
1270	else if (in == 7)	/* control g	*/
1271		move_rel('u', max(5, (last_line - 5)));
1272	else if (in == 8)	/* control h	*/
1273		delete(TRUE);
1274	else if (in == 9)	/* control i	*/
1275		;
1276	else if (in == 10)	/* control j	*/
1277		undel_char();
1278	else if (in == 11)	/* control k	*/
1279		del_line();
1280	else if (in == 12)	/* control l	*/
1281		undel_line();
1282	else if (in == 13)	/* control m	*/
1283		insert_line(TRUE);
1284	else if (in == 14)	/* control n	*/
1285		down();
1286	else if (in == 15)	/* control o	*/
1287	{
1288		string = get_string(ascii_code_str, TRUE);
1289		if (*string != '\0')
1290		{
1291			in = atoi(string);
1292			wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1293			insert(in);
1294		}
1295		free(string);
1296	}
1297	else if (in == 16)	/* control p	*/
1298		up();
1299	else if (in == 17)	/* control q	*/
1300		;
1301	else if (in == 18)	/* control r	*/
1302		undel_word();
1303	else if (in == 19)	/* control s	*/
1304		;
1305	else if (in == 20)	/* control t	*/
1306		top();
1307	else if (in == 21)	/* control u	*/
1308		bottom();
1309	else if (in == 22)	/* control v	*/
1310		move_rel('d', max(5, (last_line - 5)));
1311	else if (in == 23)	/* control w	*/
1312		del_word();
1313	else if (in == 24)	/* control x	*/
1314		search(TRUE);
1315	else if (in == 25)	/* control y	*/
1316		search_prompt();
1317	else if (in == 26)	/* control z	*/
1318		adv_word();
1319	else if (in == 27)	/* control [ (escape)	*/
1320	{
1321		menu_op(main_menu);
1322	}
1323}
1324
1325/* go to bottom of file			*/
1326void
1327bottom(void)
1328{
1329	while (curr_line->next_line != NULL)
1330	{
1331		curr_line = curr_line->next_line;
1332		absolute_lin++;
1333	}
1334	point = curr_line->line;
1335	if (horiz_offset)
1336		horiz_offset = 0;
1337	position = 1;
1338	midscreen(last_line, point);
1339	scr_pos = scr_horz;
1340}
1341
1342/* go to top of file			*/
1343void
1344top(void)
1345{
1346	while (curr_line->prev_line != NULL)
1347	{
1348		curr_line = curr_line->prev_line;
1349		absolute_lin--;
1350	}
1351	point = curr_line->line;
1352	if (horiz_offset)
1353		horiz_offset = 0;
1354	position = 1;
1355	midscreen(0, point);
1356	scr_pos = scr_horz;
1357}
1358
1359/* move pointers to start of next line	*/
1360void
1361nextline(void)
1362{
1363	curr_line = curr_line->next_line;
1364	absolute_lin++;
1365	point = curr_line->line;
1366	position = 1;
1367	if (scr_vert == last_line)
1368	{
1369		wmove(text_win, 0,0);
1370		wdeleteln(text_win);
1371		wmove(text_win, last_line,0);
1372		wclrtobot(text_win);
1373		draw_line(last_line,0,point,1,curr_line->line_length);
1374	}
1375	else
1376		scr_vert++;
1377}
1378
1379/* move pointers to start of previous line*/
1380void
1381prevline(void)
1382{
1383	curr_line = curr_line->prev_line;
1384	absolute_lin--;
1385	point = curr_line->line;
1386	position = 1;
1387	if (scr_vert == 0)
1388	{
1389		winsertln(text_win);
1390		draw_line(0,0,point,1,curr_line->line_length);
1391	}
1392	else
1393		scr_vert--;
1394	while (position < curr_line->line_length)
1395	{
1396		position++;
1397		point++;
1398	}
1399}
1400
1401/* move left one character	*/
1402void
1403left(int disp)
1404{
1405	if (point != curr_line->line)	/* if not at begin of line	*/
1406	{
1407		if ((ee_chinese) && (position >= 2) && (*(point - 2) > 127))
1408		{
1409			point--;
1410			position--;
1411		}
1412		point--;
1413		position--;
1414		scanline(point);
1415		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1416		scr_pos = scr_horz;
1417	}
1418	else if (curr_line->prev_line != NULL)
1419	{
1420		if (!disp)
1421		{
1422			absolute_lin--;
1423			curr_line = curr_line->prev_line;
1424			point = curr_line->line + curr_line->line_length;
1425			position = curr_line->line_length;
1426			return;
1427		}
1428		position = 1;
1429		prevline();
1430		scanline(point);
1431		scr_pos = scr_horz;
1432		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1433	}
1434}
1435
1436/* move right one character	*/
1437void
1438right(int disp)
1439{
1440	if (position < curr_line->line_length)
1441	{
1442		if ((ee_chinese) && (*point > 127) &&
1443		    ((curr_line->line_length - position) >= 2))
1444		{
1445			point++;
1446			position++;
1447		}
1448		point++;
1449		position++;
1450		scanline(point);
1451		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1452		scr_pos = scr_horz;
1453	}
1454	else if (curr_line->next_line != NULL)
1455	{
1456		if (!disp)
1457		{
1458			absolute_lin++;
1459			curr_line = curr_line->next_line;
1460			point = curr_line->line;
1461			position = 1;
1462			return;
1463		}
1464		nextline();
1465		scr_pos = scr_horz = 0;
1466		if (horiz_offset)
1467		{
1468			horiz_offset = 0;
1469			midscreen(scr_vert, point);
1470		}
1471		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1472		position = 1;
1473	}
1474}
1475
1476/* move to the same column as on other line	*/
1477void
1478find_pos(void)
1479{
1480	scr_horz = 0;
1481	position = 1;
1482	while ((scr_horz < scr_pos) && (position < curr_line->line_length))
1483	{
1484		if (*point == 9)
1485			scr_horz += tabshift(scr_horz);
1486		else if (*point < ' ')
1487			scr_horz += 2;
1488		else if ((ee_chinese) && (*point > 127) &&
1489		    ((curr_line->line_length - position) >= 2))
1490		{
1491			scr_horz += 2;
1492			point++;
1493			position++;
1494		}
1495		else
1496			scr_horz++;
1497		position++;
1498		point++;
1499	}
1500	if ((scr_horz - horiz_offset) > last_col)
1501	{
1502		horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
1503		midscreen(scr_vert, point);
1504	}
1505	else if (scr_horz < horiz_offset)
1506	{
1507		horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
1508		midscreen(scr_vert, point);
1509	}
1510	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1511}
1512
1513/* move up one line		*/
1514void
1515up(void)
1516{
1517	if (curr_line->prev_line != NULL)
1518	{
1519		prevline();
1520		point = curr_line->line;
1521		find_pos();
1522	}
1523}
1524
1525/* move down one line		*/
1526void
1527down(void)
1528{
1529	if (curr_line->next_line != NULL)
1530	{
1531		nextline();
1532		find_pos();
1533	}
1534}
1535
1536/* process function key		*/
1537void
1538function_key(void)
1539{
1540	if (in == KEY_LEFT)
1541		left(TRUE);
1542	else if (in == KEY_RIGHT)
1543		right(TRUE);
1544	else if (in == KEY_HOME)
1545		bol();
1546	else if (in == KEY_END)
1547		eol();
1548	else if (in == KEY_UP)
1549		up();
1550	else if (in == KEY_DOWN)
1551		down();
1552	else if (in == KEY_NPAGE)
1553		move_rel('d', max( 5, (last_line - 5)));
1554	else if (in == KEY_PPAGE)
1555		move_rel('u', max(5, (last_line - 5)));
1556	else if (in == KEY_DL)
1557		del_line();
1558	else if (in == KEY_DC)
1559		del_char();
1560	else if (in == KEY_BACKSPACE)
1561		delete(TRUE);
1562	else if (in == KEY_IL)
1563	{		/* insert a line before current line	*/
1564		insert_line(TRUE);
1565		left(TRUE);
1566	}
1567	else if (in == KEY_F(1))
1568		gold = !gold;
1569	else if (in == KEY_F(2))
1570	{
1571		if (gold)
1572		{
1573			gold = FALSE;
1574			undel_line();
1575		}
1576		else
1577			undel_char();
1578	}
1579	else if (in == KEY_F(3))
1580	{
1581		if (gold)
1582		{
1583			gold = FALSE;
1584			undel_word();
1585		}
1586		else
1587			del_word();
1588	}
1589	else if (in == KEY_F(4))
1590	{
1591		if (gold)
1592		{
1593			gold = FALSE;
1594			paint_info_win();
1595			midscreen(scr_vert, point);
1596		}
1597		else
1598			adv_word();
1599	}
1600	else if (in == KEY_F(5))
1601	{
1602		if (gold)
1603		{
1604			gold = FALSE;
1605			search_prompt();
1606		}
1607		else
1608			search(TRUE);
1609	}
1610	else if (in == KEY_F(6))
1611	{
1612		if (gold)
1613		{
1614			gold = FALSE;
1615			bottom();
1616		}
1617		else
1618			top();
1619	}
1620	else if (in == KEY_F(7))
1621	{
1622		if (gold)
1623		{
1624			gold = FALSE;
1625			eol();
1626		}
1627		else
1628			bol();
1629	}
1630	else if (in == KEY_F(8))
1631	{
1632		if (gold)
1633		{
1634			gold = FALSE;
1635			command_prompt();
1636		}
1637		else
1638			adv_line();
1639	}
1640}
1641
1642void
1643print_buffer(void)
1644{
1645	char buffer[256];
1646
1647	sprintf(buffer, ">!%s", print_command);
1648	wmove(com_win, 0, 0);
1649	wclrtoeol(com_win);
1650	wprintw(com_win, printer_msg_str, print_command);
1651	wrefresh(com_win);
1652	command(buffer);
1653}
1654
1655void
1656command_prompt(void)
1657{
1658	char *cmd_str;
1659	int result;
1660
1661	info_type = COMMANDS;
1662	paint_info_win();
1663	cmd_str = get_string(command_str, TRUE);
1664	if ((result = unique_test(cmd_str, commands)) != 1)
1665	{
1666		werase(com_win);
1667		wmove(com_win, 0, 0);
1668		if (result == 0)
1669			wprintw(com_win, unkn_cmd_str, cmd_str);
1670		else
1671			wprintw(com_win, non_unique_cmd_msg);
1672
1673		wrefresh(com_win);
1674
1675		info_type = CONTROL_KEYS;
1676		paint_info_win();
1677
1678		if (cmd_str != NULL)
1679			free(cmd_str);
1680		return;
1681	}
1682	command(cmd_str);
1683	wrefresh(com_win);
1684	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
1685	info_type = CONTROL_KEYS;
1686	paint_info_win();
1687	if (cmd_str != NULL)
1688		free(cmd_str);
1689}
1690
1691/* process commands from keyboard	*/
1692void
1693command(char *cmd_str1)
1694{
1695	char *cmd_str2 = NULL;
1696	char *cmd_str = cmd_str1;
1697
1698	clear_com_win = TRUE;
1699	if (compare(cmd_str, HELP, FALSE))
1700		help();
1701	else if (compare(cmd_str, WRITE, FALSE))
1702	{
1703		if (restrict_mode())
1704		{
1705			return;
1706		}
1707		cmd_str = next_word(cmd_str);
1708		if (*cmd_str == '\0')
1709		{
1710			cmd_str = cmd_str2 = get_string(file_write_prompt_str, TRUE);
1711		}
1712		tmp_file = resolve_name(cmd_str);
1713		write_file(tmp_file, 1);
1714		if (tmp_file != cmd_str)
1715			free(tmp_file);
1716	}
1717	else if (compare(cmd_str, READ, FALSE))
1718	{
1719		if (restrict_mode())
1720		{
1721			return;
1722		}
1723		cmd_str = next_word(cmd_str);
1724		if (*cmd_str == '\0')
1725		{
1726			cmd_str = cmd_str2 = get_string(file_read_prompt_str, TRUE);
1727		}
1728		tmp_file = cmd_str;
1729		recv_file = TRUE;
1730		tmp_file = resolve_name(cmd_str);
1731		check_fp();
1732		if (tmp_file != cmd_str)
1733			free(tmp_file);
1734	}
1735	else if (compare(cmd_str, LINE, FALSE))
1736	{
1737		wmove(com_win, 0, 0);
1738		wclrtoeol(com_win);
1739		wprintw(com_win, line_num_str, curr_line->line_number);
1740		wprintw(com_win, line_len_str, curr_line->line_length);
1741	}
1742	else if (compare(cmd_str, FILE_str, FALSE))
1743	{
1744		wmove(com_win, 0, 0);
1745		wclrtoeol(com_win);
1746		if (in_file_name == NULL)
1747			wprintw(com_win, no_file_string);
1748		else
1749			wprintw(com_win, current_file_str, in_file_name);
1750	}
1751	else if ((*cmd_str >= '0') && (*cmd_str <= '9'))
1752		goto_line(cmd_str);
1753	else if (compare(cmd_str, CHARACTER, FALSE))
1754	{
1755		wmove(com_win, 0, 0);
1756		wclrtoeol(com_win);
1757		wprintw(com_win, char_str, *point);
1758	}
1759	else if (compare(cmd_str, REDRAW, FALSE))
1760		redraw();
1761	else if (compare(cmd_str, RESEQUENCE, FALSE))
1762	{
1763		tmp_line = first_line->next_line;
1764		while (tmp_line != NULL)
1765		{
1766		tmp_line->line_number = tmp_line->prev_line->line_number + 1;
1767			tmp_line = tmp_line->next_line;
1768		}
1769	}
1770	else if (compare(cmd_str, AUTHOR, FALSE))
1771	{
1772		wmove(com_win, 0, 0);
1773		wclrtoeol(com_win);
1774		wprintw(com_win, "written by Hugh Mahon");
1775	}
1776	else if (compare(cmd_str, VERSION, FALSE))
1777	{
1778		wmove(com_win, 0, 0);
1779		wclrtoeol(com_win);
1780		wprintw(com_win, "%s", version);
1781	}
1782	else if (compare(cmd_str, CASE, FALSE))
1783		case_sen = TRUE;
1784	else if (compare(cmd_str, NOCASE, FALSE))
1785		case_sen = FALSE;
1786	else if (compare(cmd_str, EXPAND, FALSE))
1787		expand_tabs = TRUE;
1788	else if (compare(cmd_str, NOEXPAND, FALSE))
1789		expand_tabs = FALSE;
1790	else if (compare(cmd_str, Exit_string, FALSE))
1791		finish();
1792	else if (compare(cmd_str, chinese_cmd, FALSE))
1793	{
1794		ee_chinese = TRUE;
1795#ifdef NCURSE
1796		nc_setattrib(A_NC_BIG5);
1797#endif /* NCURSE */
1798	}
1799	else if (compare(cmd_str, nochinese_cmd, FALSE))
1800	{
1801		ee_chinese = FALSE;
1802#ifdef NCURSE
1803		nc_clearattrib(A_NC_BIG5);
1804#endif /* NCURSE */
1805	}
1806	else if (compare(cmd_str, QUIT_string, FALSE))
1807		quit(0);
1808	else if (*cmd_str == '!')
1809	{
1810		cmd_str++;
1811		if ((*cmd_str == ' ') || (*cmd_str == 9))
1812			cmd_str = next_word(cmd_str);
1813		sh_command(cmd_str);
1814	}
1815	else if ((*cmd_str == '<') && (!in_pipe))
1816	{
1817		in_pipe = TRUE;
1818		shell_fork = FALSE;
1819		cmd_str++;
1820		if ((*cmd_str == ' ') || (*cmd_str == '\t'))
1821			cmd_str = next_word(cmd_str);
1822		command(cmd_str);
1823		in_pipe = FALSE;
1824		shell_fork = TRUE;
1825	}
1826	else if ((*cmd_str == '>') && (!out_pipe))
1827	{
1828		out_pipe = TRUE;
1829		cmd_str++;
1830		if ((*cmd_str == ' ') || (*cmd_str == '\t'))
1831			cmd_str = next_word(cmd_str);
1832		command(cmd_str);
1833		out_pipe = FALSE;
1834	}
1835	else
1836	{
1837		wmove(com_win, 0, 0);
1838		wclrtoeol(com_win);
1839		wprintw(com_win, unkn_cmd_str, cmd_str);
1840	}
1841	if (cmd_str2 != NULL)
1842		free(cmd_str2);
1843}
1844
1845/* determine horizontal position for get_string	*/
1846int
1847scan(char *line, int offset, int column)
1848{
1849	char *stemp;
1850	int i;
1851	int j;
1852
1853	stemp = line;
1854	i = 0;
1855	j = column;
1856	while (i < offset)
1857	{
1858		i++;
1859		j += len_char(*stemp, j);
1860		stemp++;
1861	}
1862	return(j);
1863}
1864
1865/* read string from input on command line */
1866char *
1867get_string(char *prompt, int advance)
1868{
1869	char *string;
1870	char *tmp_string;
1871	char *nam_str;
1872	char *g_point;
1873	int tmp_int;
1874	int g_horz, g_position, g_pos;
1875	int esc_flag;
1876
1877	g_point = tmp_string = malloc(512);
1878	wmove(com_win,0,0);
1879	wclrtoeol(com_win);
1880	waddstr(com_win, prompt);
1881	wrefresh(com_win);
1882	nam_str = tmp_string;
1883	clear_com_win = TRUE;
1884	g_horz = g_position = scan(prompt, strlen(prompt), 0);
1885	g_pos = 0;
1886	do
1887	{
1888		esc_flag = FALSE;
1889		in = wgetch(com_win);
1890		if (in == -1)
1891			exit(0);
1892		if (((in == 8) || (in == 127) || (in == KEY_BACKSPACE)) && (g_pos > 0))
1893		{
1894			tmp_int = g_horz;
1895			g_pos--;
1896			g_horz = scan(g_point, g_pos, g_position);
1897			tmp_int = tmp_int - g_horz;
1898			for (; 0 < tmp_int; tmp_int--)
1899			{
1900				if ((g_horz+tmp_int) < (last_col - 1))
1901				{
1902					waddch(com_win, '\010');
1903					waddch(com_win, ' ');
1904					waddch(com_win, '\010');
1905				}
1906			}
1907			nam_str--;
1908		}
1909		else if ((in != 8) && (in != 127) && (in != '\n') && (in != '\r') && (in < 256))
1910		{
1911			if (in == '\026')	/* control-v, accept next character verbatim	*/
1912			{			/* allows entry of ^m, ^j, and ^h	*/
1913				esc_flag = TRUE;
1914				in = wgetch(com_win);
1915				if (in == -1)
1916					exit(0);
1917			}
1918			*nam_str = in;
1919			g_pos++;
1920			if (!isprint((unsigned char)in) && (g_horz < (last_col - 1)))
1921				g_horz += out_char(com_win, in, g_horz);
1922			else
1923			{
1924				g_horz++;
1925				if (g_horz < (last_col - 1))
1926					waddch(com_win, (unsigned char)in);
1927			}
1928			nam_str++;
1929		}
1930		wrefresh(com_win);
1931		if (esc_flag)
1932			in = '\0';
1933	} while ((in != '\n') && (in != '\r'));
1934	*nam_str = '\0';
1935	nam_str = tmp_string;
1936	if (((*nam_str == ' ') || (*nam_str == 9)) && (advance))
1937		nam_str = next_word(nam_str);
1938	string = malloc(strlen(nam_str) + 1);
1939	strcpy(string, nam_str);
1940	free(tmp_string);
1941	wrefresh(com_win);
1942	return(string);
1943}
1944
1945/* compare two strings	*/
1946int
1947compare(char *string1, char *string2, int sensitive)
1948{
1949	char *strng1;
1950	char *strng2;
1951	int equal;
1952
1953	strng1 = string1;
1954	strng2 = string2;
1955	if ((strng1 == NULL) || (strng2 == NULL) || (*strng1 == '\0') || (*strng2 == '\0'))
1956		return(FALSE);
1957	equal = TRUE;
1958	while (equal)
1959	{
1960		if (sensitive)
1961		{
1962			if (*strng1 != *strng2)
1963				equal = FALSE;
1964		}
1965		else
1966		{
1967			if (toupper((unsigned char)*strng1) != toupper((unsigned char)*strng2))
1968				equal = FALSE;
1969		}
1970		strng1++;
1971		strng2++;
1972		if ((*strng1 == '\0') || (*strng2 == '\0') || (*strng1 == ' ') || (*strng2 == ' '))
1973			break;
1974	}
1975	return(equal);
1976}
1977
1978void
1979goto_line(char *cmd_str)
1980{
1981	int number;
1982	int i;
1983	char *ptr;
1984	char direction = '\0';
1985	struct text *t_line;
1986
1987	ptr = cmd_str;
1988	i= 0;
1989	while ((*ptr >='0') && (*ptr <= '9'))
1990	{
1991		i= i * 10 + (*ptr - '0');
1992		ptr++;
1993	}
1994	number = i;
1995	i = 0;
1996	t_line = curr_line;
1997	while ((t_line->line_number > number) && (t_line->prev_line != NULL))
1998	{
1999		i++;
2000		t_line = t_line->prev_line;
2001		direction = 'u';
2002	}
2003	while ((t_line->line_number < number) && (t_line->next_line != NULL))
2004	{
2005		i++;
2006		direction = 'd';
2007		t_line = t_line->next_line;
2008	}
2009	if ((i < 30) && (i > 0))
2010	{
2011		move_rel(direction, i);
2012	}
2013	else
2014	{
2015		if (direction != 'd')
2016		{
2017			absolute_lin += i;
2018		}
2019		else
2020		{
2021			absolute_lin -= i;
2022		}
2023		curr_line = t_line;
2024		point = curr_line->line;
2025		position = 1;
2026		midscreen((last_line / 2), point);
2027		scr_pos = scr_horz;
2028	}
2029	wmove(com_win, 0, 0);
2030	wclrtoeol(com_win);
2031	wprintw(com_win, line_num_str, curr_line->line_number);
2032	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
2033}
2034
2035/* put current line in middle of screen	*/
2036void
2037midscreen(int line, unsigned char *pnt)
2038{
2039	struct text *mid_line;
2040	int i;
2041
2042	line = min(line, last_line);
2043	mid_line = curr_line;
2044	for (i = 0; ((i < line) && (curr_line->prev_line != NULL)); i++)
2045		curr_line = curr_line->prev_line;
2046	scr_vert = scr_horz = 0;
2047	wmove(text_win, 0, 0);
2048	draw_screen();
2049	scr_vert = i;
2050	curr_line = mid_line;
2051	scanline(pnt);
2052	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
2053}
2054
2055/* get arguments from command line	*/
2056void
2057get_options(int numargs, char *arguments[])
2058{
2059	char *buff;
2060	int count;
2061	struct files *temp_names = NULL;
2062	char *name;
2063	char *ptr;
2064	int no_more_opts = FALSE;
2065
2066	/*
2067	 |	see if editor was invoked as 'ree' (restricted mode)
2068	 */
2069
2070	if (!(name = strrchr(arguments[0], '/')))
2071		name = arguments[0];
2072	else
2073		name++;
2074	if (!strcmp(name, "ree"))
2075		restricted = TRUE;
2076
2077	top_of_stack = NULL;
2078	input_file = FALSE;
2079	recv_file = FALSE;
2080	count = 1;
2081	while ((count < numargs)&& (!no_more_opts))
2082	{
2083		buff = arguments[count];
2084		if (!strcmp("-i", buff))
2085		{
2086			info_window = FALSE;
2087		}
2088		else if (!strcmp("-e", buff))
2089		{
2090			expand_tabs = FALSE;
2091		}
2092		else if (!strcmp("-h", buff))
2093		{
2094			nohighlight = TRUE;
2095		}
2096		else if (!strcmp("-?", buff))
2097		{
2098			fprintf(stderr, usage0, arguments[0]);
2099			fputs(usage1, stderr);
2100			fputs(usage2, stderr);
2101			fputs(usage3, stderr);
2102			fputs(usage4, stderr);
2103			exit(1);
2104		}
2105		else if ((*buff == '+') && (start_at_line == NULL))
2106		{
2107			buff++;
2108			start_at_line = buff;
2109		}
2110		else if (!(strcmp("--", buff)))
2111			no_more_opts = TRUE;
2112		else
2113		{
2114			count--;
2115			no_more_opts = TRUE;
2116		}
2117		count++;
2118	}
2119	while (count < numargs)
2120	{
2121		buff = arguments[count];
2122		if (top_of_stack == NULL)
2123		{
2124			temp_names = top_of_stack = name_alloc();
2125		}
2126		else
2127		{
2128			temp_names->next_name = name_alloc();
2129			temp_names = temp_names->next_name;
2130		}
2131		ptr = temp_names->name = malloc(strlen(buff) + 1);
2132		while (*buff != '\0')
2133		{
2134			*ptr = *buff;
2135			buff++;
2136			ptr++;
2137		}
2138		*ptr = '\0';
2139		temp_names->next_name = NULL;
2140		input_file = TRUE;
2141		recv_file = TRUE;
2142		count++;
2143	}
2144}
2145
2146/* open or close files according to flags */
2147void
2148check_fp(void)
2149{
2150	int line_num;
2151	int temp;
2152	struct stat buf;
2153
2154	clear_com_win = TRUE;
2155	tmp_vert = scr_vert;
2156	tmp_horz = scr_horz;
2157	tmp_line = curr_line;
2158	if (input_file)
2159	{
2160		in_file_name = tmp_file = top_of_stack->name;
2161		top_of_stack = top_of_stack->next_name;
2162	}
2163	temp = stat(tmp_file, &buf);
2164	buf.st_mode &= ~07777;
2165	if ((temp != -1) && (buf.st_mode != 0100000) && (buf.st_mode != 0))
2166	{
2167		wprintw(com_win, file_is_dir_msg, tmp_file);
2168		wrefresh(com_win);
2169		if (input_file)
2170		{
2171			quit(0);
2172			return;
2173		}
2174		else
2175			return;
2176	}
2177	if ((get_fd = open(tmp_file, O_RDONLY)) == -1)
2178	{
2179		wmove(com_win, 0, 0);
2180		wclrtoeol(com_win);
2181		if (input_file)
2182			wprintw(com_win, new_file_msg, tmp_file);
2183		else
2184			wprintw(com_win, cant_open_msg, tmp_file);
2185		wrefresh(com_win);
2186		wmove(text_win, scr_vert, (scr_horz - horiz_offset));
2187		wrefresh(text_win);
2188		recv_file = FALSE;
2189		input_file = FALSE;
2190		return;
2191	}
2192	else
2193		get_file(tmp_file);
2194
2195	recv_file = FALSE;
2196	line_num = curr_line->line_number;
2197	scr_vert = tmp_vert;
2198	scr_horz = tmp_horz;
2199	if (input_file)
2200		curr_line= first_line;
2201	else
2202		curr_line = tmp_line;
2203	point = curr_line->line;
2204	draw_screen();
2205	if (input_file)
2206	{
2207		input_file = FALSE;
2208		if (start_at_line != NULL)
2209		{
2210			line_num = atoi(start_at_line) - 1;
2211			move_rel('d', line_num);
2212			line_num = 0;
2213			start_at_line = NULL;
2214		}
2215	}
2216	else
2217	{
2218		wmove(com_win, 0, 0);
2219		wclrtoeol(com_win);
2220		text_changes = TRUE;
2221		if ((tmp_file != NULL) && (*tmp_file != '\0'))
2222			wprintw(com_win, file_read_fin_msg, tmp_file);
2223	}
2224	wrefresh(com_win);
2225	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
2226	wrefresh(text_win);
2227}
2228
2229/* read specified file into current buffer	*/
2230void
2231get_file(char *file_name)
2232{
2233	int can_read;		/* file has at least one character	*/
2234	int length;		/* length of line read by read		*/
2235	int append;		/* should text be appended to current line */
2236	struct text *temp_line;
2237	char ro_flag = FALSE;
2238
2239	if (recv_file)		/* if reading a file			*/
2240	{
2241		wmove(com_win, 0, 0);
2242		wclrtoeol(com_win);
2243		wprintw(com_win, reading_file_msg, file_name);
2244		if (access(file_name, 2))	/* check permission to write */
2245		{
2246			if ((errno == ENOTDIR) || (errno == EACCES) || (errno == EROFS) || (errno == ETXTBSY) || (errno == EFAULT))
2247			{
2248				wprintw(com_win, read_only_msg);
2249				ro_flag = TRUE;
2250			}
2251		}
2252		wrefresh(com_win);
2253	}
2254	if (curr_line->line_length > 1)	/* if current line is not blank	*/
2255	{
2256		insert_line(FALSE);
2257		left(FALSE);
2258		append = FALSE;
2259	}
2260	else
2261		append = TRUE;
2262	can_read = FALSE;		/* test if file has any characters  */
2263	while (((length = read(get_fd, in_string, 512)) != 0) && (length != -1))
2264	{
2265		can_read = TRUE;  /* if set file has at least 1 character   */
2266		get_line(length, in_string, &append);
2267	}
2268	if ((can_read) && (curr_line->line_length == 1))
2269	{
2270		temp_line = curr_line->prev_line;
2271		temp_line->next_line = curr_line->next_line;
2272		if (temp_line->next_line != NULL)
2273			temp_line->next_line->prev_line = temp_line;
2274		if (curr_line->line != NULL)
2275			free(curr_line->line);
2276		free(curr_line);
2277		curr_line = temp_line;
2278	}
2279	if (input_file)	/* if this is the file to be edited display number of lines	*/
2280	{
2281		wmove(com_win, 0, 0);
2282		wclrtoeol(com_win);
2283		wprintw(com_win, file_read_lines_msg, in_file_name, curr_line->line_number);
2284		if (ro_flag)
2285			wprintw(com_win, read_only_msg);
2286		wrefresh(com_win);
2287	}
2288	else if (can_read)	/* not input_file and file is non-zero size */
2289		text_changes = TRUE;
2290
2291	if (recv_file)		/* if reading a file			*/
2292	{
2293		in = EOF;
2294	}
2295}
2296
2297/* read string and split into lines */
2298void
2299get_line(int length, unsigned char *in_string, int *append)
2300{
2301	unsigned char *str1;
2302	unsigned char *str2;
2303	int num;		/* offset from start of string		*/
2304	int char_count;		/* length of new line (or added portion	*/
2305	int temp_counter;	/* temporary counter value		*/
2306	struct text *tline;	/* temporary pointer to new line	*/
2307	int first_time;		/* if TRUE, the first time through the loop */
2308
2309	str2 = in_string;
2310	num = 0;
2311	first_time = TRUE;
2312	while (num < length)
2313	{
2314		if (!first_time)
2315		{
2316			if (num < length)
2317			{
2318				str2++;
2319				num++;
2320			}
2321		}
2322		else
2323			first_time = FALSE;
2324		str1 = str2;
2325		char_count = 1;
2326		/* find end of line	*/
2327		while ((*str2 != '\n') && (num < length))
2328		{
2329			str2++;
2330			num++;
2331			char_count++;
2332		}
2333		if (!(*append))	/* if not append to current line, insert new one */
2334		{
2335			tline = txtalloc();	/* allocate data structure for next line */
2336			tline->line_number = curr_line->line_number + 1;
2337			tline->next_line = curr_line->next_line;
2338			tline->prev_line = curr_line;
2339			curr_line->next_line = tline;
2340			if (tline->next_line != NULL)
2341				tline->next_line->prev_line = tline;
2342			curr_line = tline;
2343			curr_line->line = point = (unsigned char *) malloc(char_count);
2344			curr_line->line_length = char_count;
2345			curr_line->max_length = char_count;
2346		}
2347		else
2348		{
2349			point = resiz_line(char_count, curr_line, curr_line->line_length);
2350			curr_line->line_length += (char_count - 1);
2351		}
2352		for (temp_counter = 1; temp_counter < char_count; temp_counter++)
2353		{
2354			*point = *str1;
2355			point++;
2356			str1++;
2357		}
2358		*point = '\0';
2359		*append = FALSE;
2360		if ((num == length) && (*str2 != '\n'))
2361			*append = TRUE;
2362	}
2363}
2364
2365void
2366draw_screen()		/* redraw the screen from current postion	*/
2367{
2368	struct text *temp_line;
2369	unsigned char *line_out;
2370	int temp_vert;
2371
2372	temp_line = curr_line;
2373	temp_vert = scr_vert;
2374	wclrtobot(text_win);
2375	while ((temp_line != NULL) && (temp_vert <= last_line))
2376	{
2377		line_out = temp_line->line;
2378		draw_line(temp_vert, 0, line_out, 1, temp_line->line_length);
2379		temp_vert++;
2380		temp_line = temp_line->next_line;
2381	}
2382	wmove(text_win, temp_vert, 0);
2383	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
2384}
2385
2386/* prepare to exit edit session	*/
2387void
2388finish(void)
2389{
2390	char *file_name = in_file_name;
2391
2392	/*
2393	 |	changes made here should be reflected in the 'save'
2394	 |	portion of file_op()
2395	 */
2396
2397	if ((file_name == NULL) || (*file_name == '\0'))
2398		file_name = get_string(save_file_name_prompt, TRUE);
2399
2400	if ((file_name == NULL) || (*file_name == '\0'))
2401	{
2402		wmove(com_win, 0, 0);
2403		wprintw(com_win, file_not_saved_msg);
2404		wclrtoeol(com_win);
2405		wrefresh(com_win);
2406		clear_com_win = TRUE;
2407		return;
2408	}
2409
2410	tmp_file = resolve_name(file_name);
2411	if (tmp_file != file_name)
2412	{
2413		free(file_name);
2414		file_name = tmp_file;
2415	}
2416
2417	if (write_file(file_name, 1))
2418	{
2419		text_changes = FALSE;
2420		quit(0);
2421	}
2422}
2423
2424/* exit editor			*/
2425int
2426quit(int noverify)
2427{
2428	char *ans;
2429
2430	touchwin(text_win);
2431	wrefresh(text_win);
2432	if ((text_changes) && (!noverify))
2433	{
2434		ans = get_string(changes_made_prompt, TRUE);
2435		if (toupper((unsigned char)*ans) == toupper((unsigned char)*yes_char))
2436			text_changes = FALSE;
2437		else
2438			return(0);
2439		free(ans);
2440	}
2441	if (top_of_stack == NULL)
2442	{
2443		if (info_window)
2444			wrefresh(info_win);
2445		wrefresh(com_win);
2446		resetty();
2447		endwin();
2448		putchar('\n');
2449		exit(0);
2450	}
2451	else
2452	{
2453		delete_text();
2454		recv_file = TRUE;
2455		input_file = TRUE;
2456		check_fp();
2457	}
2458	return(0);
2459}
2460
2461void
2462edit_abort(int arg)
2463{
2464	wrefresh(com_win);
2465	resetty();
2466	endwin();
2467	putchar('\n');
2468	exit(1);
2469}
2470
2471void
2472delete_text(void)
2473{
2474	while (curr_line->next_line != NULL)
2475		curr_line = curr_line->next_line;
2476	while (curr_line != first_line)
2477	{
2478		free(curr_line->line);
2479		curr_line = curr_line->prev_line;
2480		absolute_lin--;
2481		free(curr_line->next_line);
2482	}
2483	curr_line->next_line = NULL;
2484	*curr_line->line = '\0';
2485	curr_line->line_length = 1;
2486	curr_line->line_number = 1;
2487	point = curr_line->line;
2488	scr_pos = scr_vert = scr_horz = 0;
2489	position = 1;
2490}
2491
2492int
2493write_file(char *file_name, int warn_if_exists)
2494{
2495	char cr;
2496	char *tmp_point;
2497	struct text *out_line;
2498	int lines, charac;
2499	int temp_pos;
2500	int write_flag = TRUE;
2501
2502	charac = lines = 0;
2503	if (warn_if_exists &&
2504	    ((in_file_name == NULL) || strcmp(in_file_name, file_name)))
2505	{
2506		if ((temp_fp = fopen(file_name, "r")))
2507		{
2508			tmp_point = get_string(file_exists_prompt, TRUE);
2509			if (toupper((unsigned char)*tmp_point) == toupper((unsigned char)*yes_char))
2510				write_flag = TRUE;
2511			else
2512				write_flag = FALSE;
2513			fclose(temp_fp);
2514			free(tmp_point);
2515		}
2516	}
2517
2518	clear_com_win = TRUE;
2519
2520	if (write_flag)
2521	{
2522		if ((temp_fp = fopen(file_name, "w")) == NULL)
2523		{
2524			clear_com_win = TRUE;
2525			wmove(com_win,0,0);
2526			wclrtoeol(com_win);
2527			wprintw(com_win, create_file_fail_msg, file_name);
2528			wrefresh(com_win);
2529			return(FALSE);
2530		}
2531		else
2532		{
2533			wmove(com_win,0,0);
2534			wclrtoeol(com_win);
2535			wprintw(com_win, writing_file_msg, file_name);
2536			wrefresh(com_win);
2537			cr = '\n';
2538			out_line = first_line;
2539			while (out_line != NULL)
2540			{
2541				temp_pos = 1;
2542				tmp_point= out_line->line;
2543				while (temp_pos < out_line->line_length)
2544				{
2545					putc(*tmp_point, temp_fp);
2546					tmp_point++;
2547					temp_pos++;
2548				}
2549				charac += out_line->line_length;
2550				out_line = out_line->next_line;
2551				putc(cr, temp_fp);
2552				lines++;
2553			}
2554			fclose(temp_fp);
2555			wmove(com_win,0,0);
2556			wclrtoeol(com_win);
2557			wprintw(com_win, file_written_msg, file_name, lines, charac);
2558			wrefresh(com_win);
2559			return(TRUE);
2560		}
2561	}
2562	else
2563		return(FALSE);
2564}
2565
2566/* search for string in srch_str	*/
2567int
2568search(int display_message)
2569{
2570	int lines_moved;
2571	int iter;
2572	int found;
2573
2574	if ((srch_str == NULL) || (*srch_str == '\0'))
2575		return(FALSE);
2576	if (display_message)
2577	{
2578		wmove(com_win, 0, 0);
2579		wclrtoeol(com_win);
2580		wprintw(com_win, searching_msg);
2581		wrefresh(com_win);
2582		clear_com_win = TRUE;
2583	}
2584	lines_moved = 0;
2585	found = FALSE;
2586	srch_line = curr_line;
2587	srch_1 = point;
2588	if (position < curr_line->line_length)
2589		srch_1++;
2590	iter = position + 1;
2591	while ((!found) && (srch_line != NULL))
2592	{
2593		while ((iter < srch_line->line_length) && (!found))
2594		{
2595			srch_2 = srch_1;
2596			if (case_sen)	/* if case sensitive		*/
2597			{
2598				srch_3 = srch_str;
2599			while ((*srch_2 == *srch_3) && (*srch_3 != '\0'))
2600				{
2601					found = TRUE;
2602					srch_2++;
2603					srch_3++;
2604				}	/* end while	*/
2605			}
2606			else		/* if not case sensitive	*/
2607			{
2608				srch_3 = u_srch_str;
2609			while ((toupper(*srch_2) == *srch_3) && (*srch_3 != '\0'))
2610				{
2611					found = TRUE;
2612					srch_2++;
2613					srch_3++;
2614				}
2615			}	/* end else	*/
2616			if (!((*srch_3 == '\0') && (found)))
2617			{
2618				found = FALSE;
2619				if (iter < srch_line->line_length)
2620					srch_1++;
2621				iter++;
2622			}
2623		}
2624		if (!found)
2625		{
2626			srch_line = srch_line->next_line;
2627			if (srch_line != NULL)
2628				srch_1 = srch_line->line;
2629			iter = 1;
2630			lines_moved++;
2631		}
2632	}
2633	if (found)
2634	{
2635		if (display_message)
2636		{
2637			wmove(com_win, 0, 0);
2638			wclrtoeol(com_win);
2639			wrefresh(com_win);
2640		}
2641		if (lines_moved == 0)
2642		{
2643			while (position < iter)
2644				right(TRUE);
2645		}
2646		else
2647		{
2648			if (lines_moved < 30)
2649			{
2650				move_rel('d', lines_moved);
2651				while (position < iter)
2652					right(TRUE);
2653			}
2654			else
2655			{
2656				absolute_lin += lines_moved;
2657				curr_line = srch_line;
2658				point = srch_1;
2659				position = iter;
2660				scanline(point);
2661				scr_pos = scr_horz;
2662				midscreen((last_line / 2), point);
2663			}
2664		}
2665	}
2666	else
2667	{
2668		if (display_message)
2669		{
2670			wmove(com_win, 0, 0);
2671			wclrtoeol(com_win);
2672			wprintw(com_win, str_not_found_msg, srch_str);
2673			wrefresh(com_win);
2674		}
2675		wmove(text_win, scr_vert,(scr_horz - horiz_offset));
2676	}
2677	return(found);
2678}
2679
2680/* prompt and read search string (srch_str)	*/
2681void
2682search_prompt(void)
2683{
2684	if (srch_str != NULL)
2685		free(srch_str);
2686	if ((u_srch_str != NULL) && (*u_srch_str != '\0'))
2687		free(u_srch_str);
2688	srch_str = get_string(search_prompt_str, FALSE);
2689	gold = FALSE;
2690	srch_3 = srch_str;
2691	srch_1 = u_srch_str = malloc(strlen(srch_str) + 1);
2692	while (*srch_3 != '\0')
2693	{
2694		*srch_1 = toupper(*srch_3);
2695		srch_1++;
2696		srch_3++;
2697	}
2698	*srch_1 = '\0';
2699	search(TRUE);
2700}
2701
2702/* delete current character	*/
2703void
2704del_char(void)
2705{
2706	in = 8;  /* backspace */
2707	if (position < curr_line->line_length)	/* if not end of line	*/
2708	{
2709		if ((ee_chinese) && (*point > 127) &&
2710		    ((curr_line->line_length - position) >= 2))
2711		{
2712			point++;
2713			position++;
2714		}
2715		position++;
2716		point++;
2717		scanline(point);
2718		delete(TRUE);
2719	}
2720	else
2721	{
2722		right(TRUE);
2723		delete(TRUE);
2724	}
2725}
2726
2727/* undelete last deleted character	*/
2728void
2729undel_char(void)
2730{
2731	if (d_char[0] == '\n')	/* insert line if last del_char deleted eol */
2732		insert_line(TRUE);
2733	else
2734	{
2735		in = d_char[0];
2736		insert(in);
2737		if (d_char[1] != '\0')
2738		{
2739			in = d_char[1];
2740			insert(in);
2741		}
2742	}
2743}
2744
2745/* delete word in front of cursor	*/
2746void
2747del_word(void)
2748{
2749	int tposit;
2750	int difference;
2751	unsigned char *d_word2;
2752	unsigned char *d_word3;
2753	unsigned char tmp_char[3];
2754
2755	if (d_word != NULL)
2756		free(d_word);
2757	d_word = malloc(curr_line->line_length);
2758	tmp_char[0] = d_char[0];
2759	tmp_char[1] = d_char[1];
2760	tmp_char[2] = d_char[2];
2761	d_word3 = point;
2762	d_word2 = d_word;
2763	tposit = position;
2764	while ((tposit < curr_line->line_length) &&
2765				((*d_word3 != ' ') && (*d_word3 != '\t')))
2766	{
2767		tposit++;
2768		*d_word2 = *d_word3;
2769		d_word2++;
2770		d_word3++;
2771	}
2772	while ((tposit < curr_line->line_length) &&
2773				((*d_word3 == ' ') || (*d_word3 == '\t')))
2774	{
2775		tposit++;
2776		*d_word2 = *d_word3;
2777		d_word2++;
2778		d_word3++;
2779	}
2780	*d_word2 = '\0';
2781	d_wrd_len = difference = d_word2 - d_word;
2782	d_word2 = point;
2783	while (tposit < curr_line->line_length)
2784	{
2785		tposit++;
2786		*d_word2 = *d_word3;
2787		d_word2++;
2788		d_word3++;
2789	}
2790	curr_line->line_length -= difference;
2791	*d_word2 = '\0';
2792	draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
2793	d_char[0] = tmp_char[0];
2794	d_char[1] = tmp_char[1];
2795	d_char[2] = tmp_char[2];
2796	text_changes = TRUE;
2797	formatted = FALSE;
2798}
2799
2800/* undelete last deleted word		*/
2801void
2802undel_word(void)
2803{
2804	int temp;
2805	int tposit;
2806	unsigned char *tmp_old_ptr;
2807	unsigned char *tmp_space;
2808	unsigned char *tmp_ptr;
2809	unsigned char *d_word_ptr;
2810
2811	/*
2812	 |	resize line to handle undeleted word
2813	 */
2814	if ((curr_line->max_length - (curr_line->line_length + d_wrd_len)) < 5)
2815		point = resiz_line(d_wrd_len, curr_line, position);
2816	tmp_ptr = tmp_space = malloc(curr_line->line_length + d_wrd_len);
2817	d_word_ptr = d_word;
2818	temp = 1;
2819	/*
2820	 |	copy d_word contents into temp space
2821	 */
2822	while (temp <= d_wrd_len)
2823	{
2824		temp++;
2825		*tmp_ptr = *d_word_ptr;
2826		tmp_ptr++;
2827		d_word_ptr++;
2828	}
2829	tmp_old_ptr = point;
2830	tposit = position;
2831	/*
2832	 |	copy contents of line from curent position to eol into
2833	 |	temp space
2834	 */
2835	while (tposit < curr_line->line_length)
2836	{
2837		temp++;
2838		tposit++;
2839		*tmp_ptr = *tmp_old_ptr;
2840		tmp_ptr++;
2841		tmp_old_ptr++;
2842	}
2843	curr_line->line_length += d_wrd_len;
2844	tmp_old_ptr = point;
2845	*tmp_ptr = '\0';
2846	tmp_ptr = tmp_space;
2847	tposit = 1;
2848	/*
2849	 |	now copy contents from temp space back to original line
2850	 */
2851	while (tposit < temp)
2852	{
2853		tposit++;
2854		*tmp_old_ptr = *tmp_ptr;
2855		tmp_ptr++;
2856		tmp_old_ptr++;
2857	}
2858	*tmp_old_ptr = '\0';
2859	free(tmp_space);
2860	draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
2861}
2862
2863/* delete from cursor to end of line	*/
2864void
2865del_line(void)
2866{
2867	unsigned char *dl1;
2868	unsigned char *dl2;
2869	int tposit;
2870
2871	if (d_line != NULL)
2872		free(d_line);
2873	d_line = malloc(curr_line->line_length);
2874	dl1 = d_line;
2875	dl2 = point;
2876	tposit = position;
2877	while (tposit < curr_line->line_length)
2878	{
2879		*dl1 = *dl2;
2880		dl1++;
2881		dl2++;
2882		tposit++;
2883	}
2884	dlt_line->line_length = 1 + tposit - position;
2885	*dl1 = '\0';
2886	*point = '\0';
2887	curr_line->line_length = position;
2888	wclrtoeol(text_win);
2889	if (curr_line->next_line != NULL)
2890	{
2891		right(FALSE);
2892		delete(FALSE);
2893	}
2894	text_changes = TRUE;
2895}
2896
2897/* undelete last deleted line		*/
2898void
2899undel_line(void)
2900{
2901	unsigned char *ud1;
2902	unsigned char *ud2;
2903	int tposit;
2904
2905	if (dlt_line->line_length == 0)
2906		return;
2907
2908	insert_line(TRUE);
2909	left(TRUE);
2910	point = resiz_line(dlt_line->line_length, curr_line, position);
2911	curr_line->line_length += dlt_line->line_length - 1;
2912	ud1 = point;
2913	ud2 = d_line;
2914	tposit = 1;
2915	while (tposit < dlt_line->line_length)
2916	{
2917		tposit++;
2918		*ud1 = *ud2;
2919		ud1++;
2920		ud2++;
2921	}
2922	*ud1 = '\0';
2923	draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
2924}
2925
2926/* advance to next word		*/
2927void
2928adv_word(void)
2929{
2930while ((position < curr_line->line_length) && ((*point != 32) && (*point != 9)))
2931		right(TRUE);
2932while ((position < curr_line->line_length) && ((*point == 32) || (*point == 9)))
2933		right(TRUE);
2934}
2935
2936/* move relative to current line	*/
2937void
2938move_rel(int direction, int lines)
2939{
2940	int i;
2941	char *tmp;
2942
2943	if (direction == 'u')
2944	{
2945		scr_pos = 0;
2946		while (position > 1)
2947			left(TRUE);
2948		for (i = 0; i < lines; i++)
2949		{
2950			up();
2951		}
2952		if ((last_line > 5) && ( scr_vert < 4))
2953		{
2954			tmp = point;
2955			tmp_line = curr_line;
2956			for (i= 0;(i<5)&&(curr_line->prev_line != NULL); i++)
2957			{
2958				up();
2959			}
2960			scr_vert = scr_vert + i;
2961			curr_line = tmp_line;
2962			absolute_lin += i;
2963			point = tmp;
2964			scanline(point);
2965		}
2966	}
2967	else
2968	{
2969		if ((position != 1) && (curr_line->next_line != NULL))
2970		{
2971			nextline();
2972			scr_pos = scr_horz = 0;
2973			if (horiz_offset)
2974			{
2975				horiz_offset = 0;
2976				midscreen(scr_vert, point);
2977			}
2978		}
2979		else
2980			adv_line();
2981		for (i = 1; i < lines; i++)
2982		{
2983			down();
2984		}
2985		if ((last_line > 10) && (scr_vert > (last_line - 5)))
2986		{
2987			tmp = point;
2988			tmp_line = curr_line;
2989			for (i=0; (i<5) && (curr_line->next_line != NULL); i++)
2990			{
2991				down();
2992			}
2993			absolute_lin -= i;
2994			scr_vert = scr_vert - i;
2995			curr_line = tmp_line;
2996			point = tmp;
2997			scanline(point);
2998		}
2999	}
3000	wmove(text_win, scr_vert, (scr_horz - horiz_offset));
3001}
3002
3003/* go to end of line			*/
3004void
3005eol(void)
3006{
3007	if (position < curr_line->line_length)
3008	{
3009		while (position < curr_line->line_length)
3010			right(TRUE);
3011	}
3012	else if (curr_line->next_line != NULL)
3013	{
3014		right(TRUE);
3015		while (position < curr_line->line_length)
3016			right(TRUE);
3017	}
3018}
3019
3020/* move to beginning of line	*/
3021void
3022bol(void)
3023{
3024	if (point != curr_line->line)
3025	{
3026		while (point != curr_line->line)
3027			left(TRUE);
3028	}
3029	else if (curr_line->prev_line != NULL)
3030	{
3031		scr_pos = 0;
3032		up();
3033	}
3034}
3035
3036/* advance to beginning of next line	*/
3037void
3038adv_line(void)
3039{
3040	if ((point != curr_line->line) || (scr_pos > 0))
3041	{
3042		while (position < curr_line->line_length)
3043			right(TRUE);
3044		right(TRUE);
3045	}
3046	else if (curr_line->next_line != NULL)
3047	{
3048		scr_pos = 0;
3049		down();
3050	}
3051}
3052
3053void
3054from_top(void)
3055{
3056	struct text *tmpline = first_line;
3057	int x = 1;
3058
3059	while ((tmpline != NULL) && (tmpline != curr_line))
3060	{
3061		x++;
3062		tmpline = tmpline->next_line;
3063	}
3064	absolute_lin = x;
3065}
3066
3067/* execute shell command			*/
3068void
3069sh_command(char *string)
3070{
3071	char *temp_point;
3072	char *last_slash;
3073	char *path;		/* directory path to executable		*/
3074	int parent;		/* zero if child, child's pid if parent	*/
3075	int value;
3076	int return_val;
3077	struct text *line_holder;
3078
3079	if (restrict_mode())
3080	{
3081		return;
3082	}
3083
3084	if (!(path = getenv("SHELL")))
3085		path = "/bin/sh";
3086	last_slash = temp_point = path;
3087	while (*temp_point != '\0')
3088	{
3089		if (*temp_point == '/')
3090			last_slash = ++temp_point;
3091		else
3092			temp_point++;
3093	}
3094
3095	/*
3096	 |	if in_pipe is true, then output of the shell operation will be
3097	 |	read by the editor, and curses doesn't need to be turned off
3098	 */
3099
3100	if (!in_pipe)
3101	{
3102		keypad(com_win, FALSE);
3103		keypad(text_win, FALSE);
3104		echo();
3105		nl();
3106		noraw();
3107		resetty();
3108
3109#ifndef NCURSE
3110		endwin();
3111#endif
3112	}
3113
3114	if (in_pipe)
3115	{
3116		pipe(pipe_in);		/* create a pipe	*/
3117		parent = fork();
3118		if (!parent)		/* if the child		*/
3119		{
3120/*
3121 |  child process which will fork and exec shell command (if shell output is
3122 |  to be read by editor)
3123 */
3124			in_pipe = FALSE;
3125/*
3126 |  redirect stdout to pipe
3127 */
3128			temp_stdout = dup(1);
3129			close(1);
3130			dup(pipe_in[1]);
3131/*
3132 |  redirect stderr to pipe
3133 */
3134			temp_stderr = dup(2);
3135			close(2);
3136			dup(pipe_in[1]);
3137			close(pipe_in[1]);
3138			/*
3139			 |	child will now continue down 'if (!in_pipe)'
3140			 |	path below
3141			 */
3142		}
3143		else  /* if the parent	*/
3144		{
3145/*
3146 |  prepare editor to read from the pipe
3147 */
3148			signal(SIGCHLD, SIG_IGN);
3149			line_holder = curr_line;
3150			tmp_vert = scr_vert;
3151			close(pipe_in[1]);
3152			get_fd = pipe_in[0];
3153			get_file("");
3154			close(pipe_in[0]);
3155			scr_vert = tmp_vert;
3156			scr_horz = scr_pos = 0;
3157			position = 1;
3158			curr_line = line_holder;
3159			from_top();
3160			point = curr_line->line;
3161			out_pipe = FALSE;
3162			signal(SIGCHLD, SIG_DFL);
3163/*
3164 |  since flag "in_pipe" is still TRUE, the path which waits for the child
3165 |  process to die will be avoided.
3166 |  (the pipe is closed, no more output can be expected)
3167 */
3168		}
3169	}
3170	if (!in_pipe)
3171	{
3172		signal(SIGINT, SIG_IGN);
3173		if (out_pipe)
3174		{
3175			pipe(pipe_out);
3176		}
3177/*
3178 |  fork process which will exec command
3179 */
3180		parent = fork();
3181		if (!parent)		/* if the child	*/
3182		{
3183			if (shell_fork)
3184				putchar('\n');
3185			if (out_pipe)
3186			{
3187/*
3188 |  prepare the child process (soon to exec a shell command) to read from the
3189 |  pipe (which will be output from the editor's buffer)
3190 */
3191				close(0);
3192				dup(pipe_out[0]);
3193				close(pipe_out[0]);
3194				close(pipe_out[1]);
3195			}
3196			for (value = 1; value < 24; value++)
3197				signal(value, SIG_DFL);
3198			execl(path, last_slash, "-c", string, NULL);
3199			fprintf(stderr, exec_err_msg, path);
3200			exit(-1);
3201		}
3202		else	/* if the parent	*/
3203		{
3204			if (out_pipe)
3205			{
3206/*
3207 |  output the contents of the buffer to the pipe (to be read by the
3208 |  process forked and exec'd above as stdin)
3209 */
3210				close(pipe_out[0]);
3211				line_holder = first_line;
3212				while (line_holder != NULL)
3213				{
3214					write(pipe_out[1], line_holder->line, (line_holder->line_length-1));
3215					write(pipe_out[1], "\n", 1);
3216					line_holder = line_holder->next_line;
3217				}
3218				close(pipe_out[1]);
3219				out_pipe = FALSE;
3220			}
3221			do
3222			{
3223				return_val = wait((int *) 0);
3224			}
3225			while ((return_val != parent) && (return_val != -1));
3226/*
3227 |  if this process is actually the child of the editor, exit.  Here's how it
3228 |  works:
3229 |  The editor forks a process.  If output must be sent to the command to be
3230 |  exec'd another process is forked, and that process (the child's child)
3231 |  will exec the command.  In this case, "shell_fork" will be FALSE.  If no
3232 |  output is to be performed to the shell command, "shell_fork" will be TRUE.
3233 |  If this is the editor process, shell_fork will be true, otherwise this is
3234 |  the child of the edit process.
3235 */
3236			if (!shell_fork)
3237				exit(0);
3238		}
3239		signal(SIGINT, edit_abort);
3240	}
3241	if (shell_fork)
3242	{
3243		fputs(continue_msg, stdout);
3244		fflush(stdout);
3245		while ((in = getchar()) != '\n')
3246			;
3247	}
3248
3249	if (!in_pipe)
3250	{
3251		fixterm();
3252		noecho();
3253		nonl();
3254		raw();
3255		keypad(text_win, TRUE);
3256		keypad(com_win, TRUE);
3257		if (info_window)
3258			clearok(info_win, TRUE);
3259	}
3260
3261	redraw();
3262}
3263
3264/* set up the terminal for operating with ae	*/
3265void
3266set_up_term(void)
3267{
3268	if (!curses_initialized)
3269	{
3270		initscr();
3271		savetty();
3272		noecho();
3273		raw();
3274		nonl();
3275		curses_initialized = TRUE;
3276	}
3277
3278	if (((LINES > 15) && (COLS >= 80)) && info_window)
3279		last_line = LINES - 8;
3280	else
3281	{
3282		info_window = FALSE;
3283		last_line = LINES - 2;
3284	}
3285
3286	idlok(stdscr, TRUE);
3287	com_win = newwin(1, COLS, (LINES - 1), 0);
3288	keypad(com_win, TRUE);
3289	idlok(com_win, TRUE);
3290	wrefresh(com_win);
3291	if (!info_window)
3292		text_win = newwin((LINES - 1), COLS, 0, 0);
3293	else
3294		text_win = newwin((LINES - 7), COLS, 6, 0);
3295	keypad(text_win, TRUE);
3296	idlok(text_win, TRUE);
3297	wrefresh(text_win);
3298	help_win = newwin((LINES - 1), COLS, 0, 0);
3299	keypad(help_win, TRUE);
3300	idlok(help_win, TRUE);
3301	if (info_window)
3302	{
3303		info_type = CONTROL_KEYS;
3304		info_win = newwin(6, COLS, 0, 0);
3305		werase(info_win);
3306		paint_info_win();
3307	}
3308
3309	last_col = COLS - 1;
3310	local_LINES = LINES;
3311	local_COLS = COLS;
3312
3313#ifdef NCURSE
3314	if (ee_chinese)
3315		nc_setattrib(A_NC_BIG5);
3316#endif /* NCURSE */
3317
3318}
3319
3320void
3321resize_check(void)
3322{
3323	if ((LINES == local_LINES) && (COLS == local_COLS))
3324		return;
3325
3326	if (info_window)
3327		delwin(info_win);
3328	delwin(text_win);
3329	delwin(com_win);
3330	delwin(help_win);
3331	set_up_term();
3332	redraw();
3333	wrefresh(text_win);
3334}
3335
3336static char item_alpha[] = "abcdefghijklmnopqrstuvwxyz0123456789 ";
3337
3338int
3339menu_op(struct menu_entries menu_list[])
3340{
3341	WINDOW *temp_win;
3342	int max_width, max_height;
3343	int x_off, y_off;
3344	int counter;
3345	int length;
3346	int input;
3347	int temp;
3348	int list_size;
3349	int top_offset;		/* offset from top where menu items start */
3350	int vert_size;		/* vertical size for menu list item display */
3351	int off_start = 1;	/* offset from start of menu items to start display */
3352
3353
3354	/*
3355	 |	determine number and width of menu items
3356	 */
3357
3358	list_size = 1;
3359	while (menu_list[list_size + 1].item_string != NULL)
3360		list_size++;
3361	max_width = 0;
3362	for (counter = 0; counter <= list_size; counter++)
3363	{
3364		if ((length = strlen(menu_list[counter].item_string)) > max_width)
3365			max_width = length;
3366	}
3367	max_width += 3;
3368	max_width = max(max_width, strlen(menu_cancel_msg));
3369	max_width = max(max_width, max(strlen(more_above_str), strlen(more_below_str)));
3370	max_width += 6;
3371
3372	/*
3373	 |	make sure that window is large enough to handle menu
3374	 |	if not, print error message and return to calling function
3375	 */
3376
3377	if (max_width > COLS)
3378	{
3379		wmove(com_win, 0, 0);
3380		werase(com_win);
3381		wprintw(com_win, menu_too_lrg_msg);
3382		wrefresh(com_win);
3383		clear_com_win = TRUE;
3384		return(0);
3385	}
3386
3387	top_offset = 0;
3388
3389	if (list_size > LINES)
3390	{
3391		max_height = LINES;
3392		if (max_height > 11)
3393			vert_size = max_height - 8;
3394		else
3395			vert_size = max_height;
3396	}
3397	else
3398	{
3399		vert_size = list_size;
3400		max_height = list_size;
3401	}
3402
3403	if (LINES >= (vert_size + 8))
3404	{
3405		if (menu_list[0].argument != MENU_WARN)
3406			max_height = vert_size + 8;
3407		else
3408			max_height = vert_size + 7;
3409		top_offset = 4;
3410	}
3411	x_off = (COLS - max_width) / 2;
3412	y_off = (LINES - max_height - 1) / 2;
3413	temp_win = newwin(max_height, max_width, y_off, x_off);
3414	keypad(temp_win, TRUE);
3415
3416	paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size);
3417
3418	counter = 1;
3419	do
3420	{
3421		if (off_start > 2)
3422			wmove(temp_win, (1 + counter + top_offset - off_start), 3);
3423		else
3424			wmove(temp_win, (counter + top_offset - off_start), 3);
3425
3426		wrefresh(temp_win);
3427		in = wgetch(temp_win);
3428		input = in;
3429		if (input == -1)
3430			exit(0);
3431
3432		if (isascii(input) && isalnum(input))
3433		{
3434			if (isalpha(input))
3435			{
3436				temp = 1 + tolower(input) - 'a';
3437			}
3438			else if (isdigit(input))
3439			{
3440				temp = (2 + 'z' - 'a') + (input - '0');
3441			}
3442
3443			if (temp <= list_size)
3444			{
3445				input = '\n';
3446				counter = temp;
3447			}
3448		}
3449		else
3450		{
3451			switch (input)
3452			{
3453				case ' ':	/* space	*/
3454				case '\004':	/* ^d, down	*/
3455				case KEY_RIGHT:
3456				case KEY_DOWN:
3457					counter++;
3458					if (counter > list_size)
3459						counter = 1;
3460					break;
3461				case '\010':	/* ^h, backspace*/
3462				case '\025':	/* ^u, up	*/
3463				case 127:	/* ^?, delete	*/
3464				case KEY_BACKSPACE:
3465				case KEY_LEFT:
3466				case KEY_UP:
3467					counter--;
3468					if (counter == 0)
3469						counter = list_size;
3470					break;
3471				case '\033':	/* escape key	*/
3472					if (menu_list[0].argument != MENU_WARN)
3473						counter = 0;
3474					break;
3475				case '\014':	/* ^l       	*/
3476				case '\022':	/* ^r, redraw	*/
3477					paint_menu(menu_list, max_width, max_height,
3478						list_size, top_offset, temp_win,
3479						off_start, vert_size);
3480					break;
3481				default:
3482					break;
3483			}
3484		}
3485
3486		if (((list_size - off_start) >= (vert_size - 1)) &&
3487			(counter > (off_start + vert_size - 3)) &&
3488				(off_start > 1))
3489		{
3490			if (counter == list_size)
3491				off_start = (list_size - vert_size) + 2;
3492			else
3493				off_start++;
3494
3495			paint_menu(menu_list, max_width, max_height,
3496				   list_size, top_offset, temp_win, off_start,
3497				   vert_size);
3498		}
3499		else if ((list_size != vert_size) &&
3500				(counter > (off_start + vert_size - 2)))
3501		{
3502			if (counter == list_size)
3503				off_start = 2 + (list_size - vert_size);
3504			else if (off_start == 1)
3505				off_start = 3;
3506			else
3507				off_start++;
3508
3509			paint_menu(menu_list, max_width, max_height,
3510				   list_size, top_offset, temp_win, off_start,
3511				   vert_size);
3512		}
3513		else if (counter < off_start)
3514		{
3515			if (counter <= 2)
3516				off_start = 1;
3517			else
3518				off_start = counter;
3519
3520			paint_menu(menu_list, max_width, max_height,
3521				   list_size, top_offset, temp_win, off_start,
3522				   vert_size);
3523		}
3524	}
3525	while ((input != '\r') && (input != '\n') && (counter != 0));
3526
3527	werase(temp_win);
3528	wrefresh(temp_win);
3529	delwin(temp_win);
3530
3531	if ((menu_list[counter].procedure != NULL) ||
3532	    (menu_list[counter].iprocedure != NULL) ||
3533	    (menu_list[counter].nprocedure != NULL))
3534	{
3535		if (menu_list[counter].argument != -1)
3536			(*menu_list[counter].iprocedure)(menu_list[counter].argument);
3537		else if (menu_list[counter].ptr_argument != NULL)
3538			(*menu_list[counter].procedure)(menu_list[counter].ptr_argument);
3539		else
3540			(*menu_list[counter].nprocedure)();
3541	}
3542
3543	if (info_window)
3544		paint_info_win();
3545	redraw();
3546
3547	return(counter);
3548}
3549
3550void
3551paint_menu(struct menu_entries menu_list[], int max_width, int max_height,
3552    int list_size, int top_offset, WINDOW *menu_win, int off_start,
3553    int vert_size)
3554{
3555	int counter, temp_int;
3556
3557	werase(menu_win);
3558
3559	/*
3560	 |	output top and bottom portions of menu box only if window
3561	 |	large enough
3562	 */
3563
3564	if (max_height > vert_size)
3565	{
3566		wmove(menu_win, 1, 1);
3567		if (!nohighlight)
3568			wstandout(menu_win);
3569		waddch(menu_win, '+');
3570		for (counter = 0; counter < (max_width - 4); counter++)
3571			waddch(menu_win, '-');
3572		waddch(menu_win, '+');
3573
3574		wmove(menu_win, (max_height - 2), 1);
3575		waddch(menu_win, '+');
3576		for (counter = 0; counter < (max_width - 4); counter++)
3577			waddch(menu_win, '-');
3578		waddch(menu_win, '+');
3579		wstandend(menu_win);
3580		wmove(menu_win, 2, 3);
3581		waddstr(menu_win, menu_list[0].item_string);
3582		wmove(menu_win, (max_height - 3), 3);
3583		if (menu_list[0].argument != MENU_WARN)
3584			waddstr(menu_win, menu_cancel_msg);
3585	}
3586	if (!nohighlight)
3587		wstandout(menu_win);
3588
3589	for (counter = 0; counter < (vert_size + top_offset); counter++)
3590	{
3591		if (top_offset == 4)
3592		{
3593			temp_int = counter + 2;
3594		}
3595		else
3596			temp_int = counter;
3597
3598		wmove(menu_win, temp_int, 1);
3599		waddch(menu_win, '|');
3600		wmove(menu_win, temp_int, (max_width - 2));
3601		waddch(menu_win, '|');
3602	}
3603	wstandend(menu_win);
3604
3605	if (list_size > vert_size)
3606	{
3607		if (off_start >= 3)
3608		{
3609			temp_int = 1;
3610			wmove(menu_win, top_offset, 3);
3611			waddstr(menu_win, more_above_str);
3612		}
3613		else
3614			temp_int = 0;
3615
3616		for (counter = off_start;
3617			((temp_int + counter - off_start) < (vert_size - 1));
3618				counter++)
3619		{
3620			wmove(menu_win, (top_offset + temp_int +
3621						(counter - off_start)), 3);
3622			if (list_size > 1)
3623				wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
3624			waddstr(menu_win, menu_list[counter].item_string);
3625		}
3626
3627		wmove(menu_win, (top_offset + (vert_size - 1)), 3);
3628
3629		if (counter == list_size)
3630		{
3631			if (list_size > 1)
3632				wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
3633			wprintw(menu_win, menu_list[counter].item_string);
3634		}
3635		else
3636			wprintw(menu_win, more_below_str);
3637	}
3638	else
3639	{
3640		for (counter = 1; counter <= list_size; counter++)
3641		{
3642			wmove(menu_win, (top_offset + counter - 1), 3);
3643			if (list_size > 1)
3644				wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
3645			waddstr(menu_win, menu_list[counter].item_string);
3646		}
3647	}
3648}
3649
3650void
3651help(void)
3652{
3653	int counter;
3654
3655	werase(help_win);
3656	clearok(help_win, TRUE);
3657	for (counter = 0; counter < 22; counter++)
3658	{
3659		wmove(help_win, counter, 0);
3660		waddstr(help_win, (emacs_keys_mode) ?
3661			emacs_help_text[counter] : help_text[counter]);
3662	}
3663	wrefresh(help_win);
3664	werase(com_win);
3665	wmove(com_win, 0, 0);
3666	wprintw(com_win, press_any_key_msg);
3667	wrefresh(com_win);
3668	counter = wgetch(com_win);
3669	if (counter == -1)
3670		exit(0);
3671	werase(com_win);
3672	wmove(com_win, 0, 0);
3673	werase(help_win);
3674	wrefresh(help_win);
3675	wrefresh(com_win);
3676	redraw();
3677}
3678
3679void
3680paint_info_win(void)
3681{
3682	int counter;
3683
3684	if (!info_window)
3685		return;
3686
3687	werase(info_win);
3688	for (counter = 0; counter < 5; counter++)
3689	{
3690		wmove(info_win, counter, 0);
3691		wclrtoeol(info_win);
3692		if (info_type == CONTROL_KEYS)
3693			waddstr(info_win, (emacs_keys_mode) ?
3694			  emacs_control_keys[counter] : control_keys[counter]);
3695		else if (info_type == COMMANDS)
3696			waddstr(info_win, command_strings[counter]);
3697	}
3698	wmove(info_win, 5, 0);
3699	if (!nohighlight)
3700		wstandout(info_win);
3701	waddstr(info_win, separator);
3702	wstandend(info_win);
3703	wrefresh(info_win);
3704}
3705
3706void
3707no_info_window(void)
3708{
3709	if (!info_window)
3710		return;
3711	delwin(info_win);
3712	delwin(text_win);
3713	info_window = FALSE;
3714	last_line = LINES - 2;
3715	text_win = newwin((LINES - 1), COLS, 0, 0);
3716	keypad(text_win, TRUE);
3717	idlok(text_win, TRUE);
3718	clearok(text_win, TRUE);
3719	midscreen(scr_vert, point);
3720	wrefresh(text_win);
3721	clear_com_win = TRUE;
3722}
3723
3724void
3725create_info_window(void)
3726{
3727	if (info_window)
3728		return;
3729	last_line = LINES - 8;
3730	delwin(text_win);
3731	text_win = newwin((LINES - 7), COLS, 6, 0);
3732	keypad(text_win, TRUE);
3733	idlok(text_win, TRUE);
3734	werase(text_win);
3735	info_window = TRUE;
3736	info_win = newwin(6, COLS, 0, 0);
3737	werase(info_win);
3738	info_type = CONTROL_KEYS;
3739	midscreen(min(scr_vert, last_line), point);
3740	clearok(info_win, TRUE);
3741	paint_info_win();
3742	wrefresh(text_win);
3743	clear_com_win = TRUE;
3744}
3745
3746int
3747file_op(int arg)
3748{
3749	char *string;
3750	int flag;
3751
3752	if (restrict_mode())
3753	{
3754		return(0);
3755	}
3756
3757	if (arg == READ_FILE)
3758	{
3759		string = get_string(file_read_prompt_str, TRUE);
3760		recv_file = TRUE;
3761		tmp_file = resolve_name(string);
3762		check_fp();
3763		if (tmp_file != string)
3764			free(tmp_file);
3765		free(string);
3766	}
3767	else if (arg == WRITE_FILE)
3768	{
3769		string = get_string(file_write_prompt_str, TRUE);
3770		tmp_file = resolve_name(string);
3771		write_file(tmp_file, 1);
3772		if (tmp_file != string)
3773			free(tmp_file);
3774		free(string);
3775	}
3776	else if (arg == SAVE_FILE)
3777	{
3778	/*
3779	 |	changes made here should be reflected in finish()
3780	 */
3781
3782		if (in_file_name)
3783			flag = TRUE;
3784		else
3785			flag = FALSE;
3786
3787		string = in_file_name;
3788		if ((string == NULL) || (*string == '\0'))
3789			string = get_string(save_file_name_prompt, TRUE);
3790		if ((string == NULL) || (*string == '\0'))
3791		{
3792			wmove(com_win, 0, 0);
3793			wprintw(com_win, file_not_saved_msg);
3794			wclrtoeol(com_win);
3795			wrefresh(com_win);
3796			clear_com_win = TRUE;
3797			return(0);
3798		}
3799		if (!flag)
3800		{
3801			tmp_file = resolve_name(string);
3802			if (tmp_file != string)
3803			{
3804				free(string);
3805				string = tmp_file;
3806			}
3807		}
3808		if (write_file(string, 1))
3809		{
3810			in_file_name = string;
3811			text_changes = FALSE;
3812		}
3813		else if (!flag)
3814			free(string);
3815	}
3816	return(0);
3817}
3818
3819void
3820shell_op(void)
3821{
3822	char *string;
3823
3824	if (((string = get_string(shell_prompt, TRUE)) != NULL) &&
3825			(*string != '\0'))
3826	{
3827		sh_command(string);
3828		free(string);
3829	}
3830}
3831
3832void
3833leave_op(void)
3834{
3835	if (text_changes)
3836	{
3837		menu_op(leave_menu);
3838	}
3839	else
3840		quit(TRUE);
3841}
3842
3843void
3844redraw(void)
3845{
3846	if (info_window)
3847        {
3848                clearok(info_win, TRUE);
3849        	paint_info_win();
3850        }
3851        else
3852		clearok(text_win, TRUE);
3853	midscreen(scr_vert, point);
3854}
3855
3856/*
3857 |	The following routines will "format" a paragraph (as defined by a
3858 |	block of text with blank lines before and after the block).
3859 */
3860
3861/* test if line has any non-space characters	*/
3862int
3863Blank_Line(struct text *test_line)
3864{
3865	unsigned char *line;
3866	int length;
3867
3868	if (test_line == NULL)
3869		return(TRUE);
3870
3871	length = 1;
3872	line = test_line->line;
3873
3874	/*
3875	 |	To handle troff/nroff documents, consider a line with a
3876	 |	period ('.') in the first column to be blank.  To handle mail
3877	 |	messages with included text, consider a line with a '>' blank.
3878	 */
3879
3880	if ((*line == '.') || (*line == '>'))
3881		return(TRUE);
3882
3883	while (((*line == ' ') || (*line == '\t')) && (length < test_line->line_length))
3884	{
3885		length++;
3886		line++;
3887	}
3888	if (length != test_line->line_length)
3889		return(FALSE);
3890	else
3891		return(TRUE);
3892}
3893
3894/* format the paragraph according to set margins	*/
3895void
3896Format(void)
3897{
3898	int string_count;
3899	int offset;
3900	int temp_case;
3901	int status;
3902	int tmp_af;
3903	int counter;
3904	unsigned char *line;
3905	unsigned char *tmp_srchstr;
3906	unsigned char *temp1, *temp2;
3907	unsigned char *temp_dword;
3908	unsigned char temp_d_char[3];
3909
3910	temp_d_char[0] = d_char[0];
3911	temp_d_char[1] = d_char[1];
3912	temp_d_char[2] = d_char[2];
3913
3914/*
3915 |	if observ_margins is not set, or the current line is blank,
3916 |	do not format the current paragraph
3917 */
3918
3919	if ((!observ_margins) || (Blank_Line(curr_line)))
3920		return;
3921
3922/*
3923 |	save the currently set flags, and clear them
3924 */
3925
3926	wmove(com_win, 0, 0);
3927	wclrtoeol(com_win);
3928	wprintw(com_win, formatting_msg);
3929	wrefresh(com_win);
3930
3931/*
3932 |	get current position in paragraph, so after formatting, the cursor
3933 |	will be in the same relative position
3934 */
3935
3936	tmp_af = auto_format;
3937	auto_format = FALSE;
3938	offset = position;
3939	if (position != 1)
3940		prev_word();
3941	temp_dword = d_word;
3942	d_word = NULL;
3943	temp_case = case_sen;
3944	case_sen = TRUE;
3945	tmp_srchstr = srch_str;
3946	temp2 = srch_str = (unsigned char *) malloc(1 + curr_line->line_length - position);
3947	if ((*point == ' ') || (*point == '\t'))
3948		adv_word();
3949	offset -= position;
3950	counter = position;
3951	line = temp1 = point;
3952	while ((*temp1 != '\0') && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length))
3953	{
3954		*temp2 = *temp1;
3955		temp2++;
3956		temp1++;
3957		counter++;
3958	}
3959	*temp2 = '\0';
3960	if (position != 1)
3961		bol();
3962	while (!Blank_Line(curr_line->prev_line))
3963		bol();
3964	string_count = 0;
3965	status = TRUE;
3966	while ((line != point) && (status))
3967	{
3968		status = search(FALSE);
3969		string_count++;
3970	}
3971
3972	wmove(com_win, 0, 0);
3973	wclrtoeol(com_win);
3974	wprintw(com_win, formatting_msg);
3975	wrefresh(com_win);
3976
3977/*
3978 |	now get back to the start of the paragraph to start formatting
3979 */
3980
3981	if (position != 1)
3982		bol();
3983	while (!Blank_Line(curr_line->prev_line))
3984		bol();
3985
3986	observ_margins = FALSE;
3987
3988/*
3989 |	Start going through lines, putting spaces at end of lines if they do
3990 |	not already exist.  Append lines together to get one long line, and
3991 |	eliminate spacing at begin of lines.
3992 */
3993
3994	while (!Blank_Line(curr_line->next_line))
3995	{
3996		eol();
3997		left(TRUE);
3998		if (*point != ' ')
3999		{
4000			right(TRUE);
4001			insert(' ');
4002		}
4003		else
4004			right(TRUE);
4005		del_char();
4006		if ((*point == ' ') || (*point == '\t'))
4007			del_word();
4008	}
4009
4010/*
4011 |	Now there is one long line.  Eliminate extra spaces within the line
4012 |	after the first word (so as not to blow away any indenting the user
4013 |	may have put in).
4014 */
4015
4016	bol();
4017	adv_word();
4018	while (position < curr_line->line_length)
4019	{
4020		if ((*point == ' ') && (*(point + 1) == ' '))
4021			del_char();
4022		else
4023			right(TRUE);
4024	}
4025
4026/*
4027 |	Now make sure there are two spaces after a '.'.
4028 */
4029
4030	bol();
4031	while (position < curr_line->line_length)
4032	{
4033		if ((*point == '.') && (*(point + 1) == ' '))
4034		{
4035			right(TRUE);
4036			insert(' ');
4037			insert(' ');
4038			while (*point == ' ')
4039				del_char();
4040		}
4041		right(TRUE);
4042	}
4043
4044	observ_margins = TRUE;
4045	bol();
4046
4047	wmove(com_win, 0, 0);
4048	wclrtoeol(com_win);
4049	wprintw(com_win, formatting_msg);
4050	wrefresh(com_win);
4051
4052/*
4053 |	create lines between margins
4054 */
4055
4056	while (position < curr_line->line_length)
4057	{
4058		while ((scr_pos < right_margin) && (position < curr_line->line_length))
4059			right(TRUE);
4060		if (position < curr_line->line_length)
4061		{
4062			prev_word();
4063			if (position == 1)
4064				adv_word();
4065			insert_line(TRUE);
4066		}
4067	}
4068
4069/*
4070 |	go back to begin of paragraph, put cursor back to original position
4071 */
4072
4073	bol();
4074	while (!Blank_Line(curr_line->prev_line))
4075		bol();
4076
4077/*
4078 |	find word cursor was in
4079 */
4080
4081	while ((status) && (string_count > 0))
4082	{
4083		search(FALSE);
4084		string_count--;
4085	}
4086
4087/*
4088 |	offset the cursor to where it was before from the start of the word
4089 */
4090
4091	while (offset > 0)
4092	{
4093		offset--;
4094		right(TRUE);
4095	}
4096
4097/*
4098 |	reset flags and strings to what they were before formatting
4099 */
4100
4101	if (d_word != NULL)
4102		free(d_word);
4103	d_word = temp_dword;
4104	case_sen = temp_case;
4105	free(srch_str);
4106	srch_str = tmp_srchstr;
4107	d_char[0] = temp_d_char[0];
4108	d_char[1] = temp_d_char[1];
4109	d_char[2] = temp_d_char[2];
4110	auto_format = tmp_af;
4111
4112	midscreen(scr_vert, point);
4113	werase(com_win);
4114	wrefresh(com_win);
4115}
4116
4117unsigned char *init_name[3] = {
4118	"/usr/share/misc/init.ee",
4119	NULL,
4120	".init.ee"
4121	};
4122
4123/* check for init file and read it if it exists	*/
4124void
4125ee_init(void)
4126{
4127	FILE *init_file;
4128	unsigned char *string;
4129	unsigned char *str1;
4130	unsigned char *str2;
4131	char *home;
4132	int counter;
4133	int temp_int;
4134
4135	string = getenv("HOME");
4136	if (string == NULL)
4137		string = "/tmp";
4138	str1 = home = malloc(strlen(string)+10);
4139	strcpy(home, string);
4140	strcat(home, "/.init.ee");
4141	init_name[1] = home;
4142	string = malloc(512);
4143
4144	for (counter = 0; counter < 3; counter++)
4145	{
4146		if (!(access(init_name[counter], 4)))
4147		{
4148			init_file = fopen(init_name[counter], "r");
4149			while ((str2 = fgets(string, 512, init_file)) != NULL)
4150			{
4151				str1 = str2 = string;
4152				while (*str2 != '\n')
4153					str2++;
4154				*str2 = '\0';
4155
4156				if (unique_test(string, init_strings) != 1)
4157					continue;
4158
4159				if (compare(str1, CASE, FALSE))
4160					case_sen = TRUE;
4161				else if (compare(str1, NOCASE, FALSE))
4162					case_sen = FALSE;
4163				else if (compare(str1, EXPAND, FALSE))
4164					expand_tabs = TRUE;
4165				else if (compare(str1, NOEXPAND, FALSE))
4166					expand_tabs = FALSE;
4167				else if (compare(str1, INFO, FALSE))
4168					info_window = TRUE;
4169				else if (compare(str1, NOINFO, FALSE))
4170					info_window = FALSE;
4171				else if (compare(str1, MARGINS, FALSE))
4172					observ_margins = TRUE;
4173				else if (compare(str1, NOMARGINS, FALSE))
4174					observ_margins = FALSE;
4175				else if (compare(str1, AUTOFORMAT, FALSE))
4176				{
4177					auto_format = TRUE;
4178					observ_margins = TRUE;
4179				}
4180				else if (compare(str1, NOAUTOFORMAT, FALSE))
4181					auto_format = FALSE;
4182				else if (compare(str1, Echo, FALSE))
4183				{
4184					str1 = next_word(str1);
4185					if (*str1 != '\0')
4186						echo_string(str1);
4187				}
4188				else if (compare(str1, PRINTCOMMAND, FALSE))
4189				{
4190					str1 = next_word(str1);
4191					print_command = malloc(strlen(str1)+1);
4192					strcpy(print_command, str1);
4193				}
4194				else if (compare(str1, RIGHTMARGIN, FALSE))
4195				{
4196					str1 = next_word(str1);
4197					if ((*str1 >= '0') && (*str1 <= '9'))
4198					{
4199						temp_int = atoi(str1);
4200						if (temp_int > 0)
4201							right_margin = temp_int;
4202					}
4203				}
4204				else if (compare(str1, HIGHLIGHT, FALSE))
4205					nohighlight = FALSE;
4206				else if (compare(str1, NOHIGHLIGHT, FALSE))
4207					nohighlight = TRUE;
4208				else if (compare(str1, EIGHTBIT, FALSE))
4209					eightbit = TRUE;
4210				else if (compare(str1, NOEIGHTBIT, FALSE))
4211				{
4212					eightbit = FALSE;
4213					ee_chinese = FALSE;
4214				}
4215				else if (compare(str1, EMACS_string, FALSE))
4216					emacs_keys_mode = TRUE;
4217				else if (compare(str1, NOEMACS_string, FALSE))
4218					emacs_keys_mode = FALSE;
4219				else if (compare(str1, chinese_cmd, FALSE))
4220				{
4221					ee_chinese = TRUE;
4222					eightbit = TRUE;
4223				}
4224				else if (compare(str1, nochinese_cmd, FALSE))
4225					ee_chinese = FALSE;
4226			}
4227			fclose(init_file);
4228		}
4229	}
4230	free(string);
4231	free(home);
4232
4233	string = getenv("LANG");
4234	if (string != NULL)
4235	{
4236		if (strcmp(string, "zh_TW.big5") == 0)
4237		{
4238			ee_chinese = TRUE;
4239			eightbit = TRUE;
4240		}
4241	}
4242}
4243
4244/*
4245 |	Save current configuration to .init.ee file in the current directory.
4246 */
4247
4248void
4249dump_ee_conf(void)
4250{
4251	FILE *init_file;
4252	FILE *old_init_file = NULL;
4253	char *file_name = ".init.ee";
4254	char *home_dir =  "~/.init.ee";
4255	char buffer[512];
4256	struct stat buf;
4257	char *string;
4258	int length;
4259	int option = 0;
4260
4261	if (restrict_mode())
4262	{
4263		return;
4264	}
4265
4266	option = menu_op(config_dump_menu);
4267
4268	werase(com_win);
4269	wmove(com_win, 0, 0);
4270
4271	if (option == 0)
4272	{
4273		wprintw(com_win, conf_not_saved_msg);
4274		wrefresh(com_win);
4275		return;
4276	}
4277	else if (option == 2)
4278		file_name = resolve_name(home_dir);
4279
4280	/*
4281	 |	If a .init.ee file exists, move it to .init.ee.old.
4282	 */
4283
4284	if (stat(file_name, &buf) != -1)
4285	{
4286		sprintf(buffer, "%s.old", file_name);
4287		unlink(buffer);
4288		link(file_name, buffer);
4289		unlink(file_name);
4290		old_init_file = fopen(buffer, "r");
4291	}
4292
4293	init_file = fopen(file_name, "w");
4294	if (init_file == NULL)
4295	{
4296		wprintw(com_win, conf_dump_err_msg);
4297		wrefresh(com_win);
4298		return;
4299	}
4300
4301	if (old_init_file != NULL)
4302	{
4303		/*
4304		 |	Copy non-configuration info into new .init.ee file.
4305		 */
4306		while ((string = fgets(buffer, 512, old_init_file)) != NULL)
4307		{
4308			length = strlen(string);
4309			string[length - 1] = '\0';
4310
4311			if (unique_test(string, init_strings) == 1)
4312			{
4313				if (compare(string, Echo, FALSE))
4314				{
4315					fprintf(init_file, "%s\n", string);
4316				}
4317			}
4318			else
4319				fprintf(init_file, "%s\n", string);
4320		}
4321
4322		fclose(old_init_file);
4323	}
4324
4325	fprintf(init_file, "%s\n", case_sen ? CASE : NOCASE);
4326	fprintf(init_file, "%s\n", expand_tabs ? EXPAND : NOEXPAND);
4327	fprintf(init_file, "%s\n", info_window ? INFO : NOINFO );
4328	fprintf(init_file, "%s\n", observ_margins ? MARGINS : NOMARGINS );
4329	fprintf(init_file, "%s\n", auto_format ? AUTOFORMAT : NOAUTOFORMAT );
4330	fprintf(init_file, "%s %s\n", PRINTCOMMAND, print_command);
4331	fprintf(init_file, "%s %d\n", RIGHTMARGIN, right_margin);
4332	fprintf(init_file, "%s\n", nohighlight ? NOHIGHLIGHT : HIGHLIGHT );
4333	fprintf(init_file, "%s\n", eightbit ? EIGHTBIT : NOEIGHTBIT );
4334	fprintf(init_file, "%s\n", emacs_keys_mode ? EMACS_string : NOEMACS_string );
4335	fprintf(init_file, "%s\n", ee_chinese ? chinese_cmd : nochinese_cmd );
4336
4337	fclose(init_file);
4338
4339	wprintw(com_win, conf_dump_success_msg, file_name);
4340	wrefresh(com_win);
4341
4342	if ((option == 2) && (file_name != home_dir))
4343	{
4344		free(file_name);
4345	}
4346}
4347
4348/* echo the given string	*/
4349void
4350echo_string(char *string)
4351{
4352	char *temp;
4353	int Counter;
4354
4355		temp = string;
4356		while (*temp != '\0')
4357		{
4358			if (*temp == '\\')
4359			{
4360				temp++;
4361				if (*temp == 'n')
4362					putchar('\n');
4363				else if (*temp == 't')
4364					putchar('\t');
4365				else if (*temp == 'b')
4366					putchar('\b');
4367				else if (*temp == 'r')
4368					putchar('\r');
4369				else if (*temp == 'f')
4370					putchar('\f');
4371				else if ((*temp == 'e') || (*temp == 'E'))
4372					putchar('\033');	/* escape */
4373				else if (*temp == '\\')
4374					putchar('\\');
4375				else if (*temp == '\'')
4376					putchar('\'');
4377				else if ((*temp >= '0') && (*temp <= '9'))
4378				{
4379					Counter = 0;
4380					while ((*temp >= '0') && (*temp <= '9'))
4381					{
4382						Counter = (8 * Counter) + (*temp - '0');
4383						temp++;
4384					}
4385					putchar(Counter);
4386					temp--;
4387				}
4388				temp++;
4389			}
4390			else
4391			{
4392				putchar(*temp);
4393				temp++;
4394			}
4395		}
4396
4397	fflush(stdout);
4398}
4399
4400/* check spelling of words in the editor	*/
4401void
4402spell_op(void)
4403{
4404	if (restrict_mode())
4405	{
4406		return;
4407	}
4408	top();			/* go to top of file		*/
4409	insert_line(FALSE);	/* create two blank lines	*/
4410	insert_line(FALSE);
4411	top();
4412	command(shell_echo_msg);
4413	adv_line();
4414	wmove(com_win, 0, 0);
4415	wprintw(com_win, spell_in_prog_msg);
4416	wrefresh(com_win);
4417	command("<>!spell");	/* send contents of buffer to command 'spell'
4418				   and read the results back into the editor */
4419}
4420
4421void
4422ispell_op(void)
4423{
4424	char template[128], *name;
4425	char string[256];
4426	int fd;
4427
4428	if (restrict_mode())
4429	{
4430		return;
4431	}
4432	(void)sprintf(template, "/tmp/ee.XXXXXXXX");
4433	fd = mkstemp(template);
4434	if (fd < 0) {
4435		wmove(com_win, 0, 0);
4436		wprintw(com_win, create_file_fail_msg, name);
4437		wrefresh(com_win);
4438		return;
4439	}
4440	close(fd);
4441	if (write_file(name, 0))
4442	{
4443		sprintf(string, "ispell %s", name);
4444		sh_command(string);
4445		delete_text();
4446		tmp_file = name;
4447		recv_file = TRUE;
4448		check_fp();
4449		unlink(name);
4450	}
4451}
4452
4453int
4454first_word_len(struct text *test_line)
4455{
4456	int counter;
4457	unsigned char *pnt;
4458
4459	if (test_line == NULL)
4460		return(0);
4461
4462	pnt = test_line->line;
4463	if ((pnt == NULL) || (*pnt == '\0') ||
4464	    (*pnt == '.') || (*pnt == '>'))
4465		return(0);
4466
4467	if ((*pnt == ' ') || (*pnt == '\t'))
4468	{
4469		pnt = next_word(pnt);
4470	}
4471
4472	if (*pnt == '\0')
4473		return(0);
4474
4475	counter = 0;
4476	while ((*pnt != '\0') && ((*pnt != ' ') && (*pnt != '\t')))
4477	{
4478		pnt++;
4479		counter++;
4480	}
4481	while ((*pnt != '\0') && ((*pnt == ' ') || (*pnt == '\t')))
4482	{
4483		pnt++;
4484		counter++;
4485	}
4486	return(counter);
4487}
4488
4489/* format the paragraph according to set margins	*/
4490void
4491Auto_Format(void)
4492{
4493	int string_count;
4494	int offset;
4495	int temp_case;
4496	int word_len;
4497	int temp_dwl;
4498	int tmp_d_line_length;
4499	int leave_loop = FALSE;
4500	int status;
4501	int counter;
4502	char not_blank;
4503	unsigned char *line;
4504	unsigned char *tmp_srchstr;
4505	unsigned char *temp1, *temp2;
4506	unsigned char *temp_dword;
4507	unsigned char temp_d_char[3];
4508	unsigned char *tmp_d_line;
4509
4510
4511	temp_d_char[0] = d_char[0];
4512	temp_d_char[1] = d_char[1];
4513	temp_d_char[2] = d_char[2];
4514
4515/*
4516 |	if observ_margins is not set, or the current line is blank,
4517 |	do not format the current paragraph
4518 */
4519
4520	if ((!observ_margins) || (Blank_Line(curr_line)))
4521		return;
4522
4523/*
4524 |	get current position in paragraph, so after formatting, the cursor
4525 |	will be in the same relative position
4526 */
4527
4528	tmp_d_line = d_line;
4529	tmp_d_line_length = dlt_line->line_length;
4530	d_line = NULL;
4531	auto_format = FALSE;
4532	offset = position;
4533	if ((position != 1) && ((*point == ' ') || (*point == '\t') || (position == curr_line->line_length) || (*point == '\0')))
4534		prev_word();
4535	temp_dword = d_word;
4536	temp_dwl = d_wrd_len;
4537	d_wrd_len = 0;
4538	d_word = NULL;
4539	temp_case = case_sen;
4540	case_sen = TRUE;
4541	tmp_srchstr = srch_str;
4542	temp2 = srch_str = (unsigned char *) malloc(1 + curr_line->line_length - position);
4543	if ((*point == ' ') || (*point == '\t'))
4544		adv_word();
4545	offset -= position;
4546	counter = position;
4547	line = temp1 = point;
4548	while ((*temp1 != '\0') && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length))
4549	{
4550		*temp2 = *temp1;
4551		temp2++;
4552		temp1++;
4553		counter++;
4554	}
4555	*temp2 = '\0';
4556	if (position != 1)
4557		bol();
4558	while (!Blank_Line(curr_line->prev_line))
4559		bol();
4560	string_count = 0;
4561	status = TRUE;
4562	while ((line != point) && (status))
4563	{
4564		status = search(FALSE);
4565		string_count++;
4566	}
4567
4568/*
4569 |	now get back to the start of the paragraph to start checking
4570 */
4571
4572	if (position != 1)
4573		bol();
4574	while (!Blank_Line(curr_line->prev_line))
4575		bol();
4576
4577/*
4578 |	Start going through lines, putting spaces at end of lines if they do
4579 |	not already exist.  Check line length, and move words to the next line
4580 |	if they cross the margin.  Then get words from the next line if they
4581 |	will fit in before the margin.
4582 */
4583
4584	counter = 0;
4585
4586	while (!leave_loop)
4587	{
4588		if (position != curr_line->line_length)
4589			eol();
4590		left(TRUE);
4591		if (*point != ' ')
4592		{
4593			right(TRUE);
4594			insert(' ');
4595		}
4596		else
4597			right(TRUE);
4598
4599		not_blank = FALSE;
4600
4601		/*
4602		 |	fill line if first word on next line will fit
4603		 |	in the line without crossing the margin
4604		 */
4605
4606		while ((curr_line->next_line != NULL) &&
4607		       ((word_len = first_word_len(curr_line->next_line)) > 0)
4608			&& ((scr_pos + word_len) < right_margin))
4609		{
4610			adv_line();
4611			if ((*point == ' ') || (*point == '\t'))
4612				adv_word();
4613			del_word();
4614			if (position != 1)
4615				bol();
4616
4617			/*
4618			 |	We know this line was not blank before, so
4619			 |	make sure that it doesn't have one of the
4620			 |	leading characters that indicate the line
4621			 |	should not be modified.
4622			 |
4623			 |	We also know that this character should not
4624			 |	be left as the first character of this line.
4625			 */
4626
4627			if ((Blank_Line(curr_line)) &&
4628			    (curr_line->line[0] != '.') &&
4629			    (curr_line->line[0] != '>'))
4630			{
4631				del_line();
4632				not_blank = FALSE;
4633			}
4634			else
4635				not_blank = TRUE;
4636
4637			/*
4638			 |   go to end of previous line
4639			 */
4640			left(TRUE);
4641			undel_word();
4642			eol();
4643			/*
4644			 |   make sure there's a space at the end of the line
4645			 */
4646			left(TRUE);
4647			if (*point != ' ')
4648			{
4649				right(TRUE);
4650				insert(' ');
4651			}
4652			else
4653				right(TRUE);
4654		}
4655
4656		/*
4657		 |	make sure line does not cross right margin
4658		 */
4659
4660		while (right_margin <= scr_pos)
4661		{
4662			prev_word();
4663			if (position != 1)
4664			{
4665				del_word();
4666				if (Blank_Line(curr_line->next_line))
4667					insert_line(TRUE);
4668				else
4669					adv_line();
4670				if ((*point == ' ') || (*point == '\t'))
4671					adv_word();
4672				undel_word();
4673				not_blank = TRUE;
4674				if (position != 1)
4675					bol();
4676				left(TRUE);
4677			}
4678		}
4679
4680		if ((!Blank_Line(curr_line->next_line)) || (not_blank))
4681		{
4682			adv_line();
4683			counter++;
4684		}
4685		else
4686			leave_loop = TRUE;
4687	}
4688
4689/*
4690 |	go back to begin of paragraph, put cursor back to original position
4691 */
4692
4693	if (position != 1)
4694		bol();
4695	while ((counter-- > 0) || (!Blank_Line(curr_line->prev_line)))
4696		bol();
4697
4698/*
4699 |	find word cursor was in
4700 */
4701
4702	status = TRUE;
4703	while ((status) && (string_count > 0))
4704	{
4705		status = search(FALSE);
4706		string_count--;
4707	}
4708
4709/*
4710 |	offset the cursor to where it was before from the start of the word
4711 */
4712
4713	while (offset > 0)
4714	{
4715		offset--;
4716		right(TRUE);
4717	}
4718
4719	if ((string_count > 0) && (offset < 0))
4720	{
4721		while (offset < 0)
4722		{
4723			offset++;
4724			left(TRUE);
4725		}
4726	}
4727
4728/*
4729 |	reset flags and strings to what they were before formatting
4730 */
4731
4732	if (d_word != NULL)
4733		free(d_word);
4734	d_word = temp_dword;
4735	d_wrd_len = temp_dwl;
4736	case_sen = temp_case;
4737	free(srch_str);
4738	srch_str = tmp_srchstr;
4739	d_char[0] = temp_d_char[0];
4740	d_char[1] = temp_d_char[1];
4741	d_char[2] = temp_d_char[2];
4742	auto_format = TRUE;
4743	dlt_line->line_length = tmp_d_line_length;
4744	d_line = tmp_d_line;
4745
4746	formatted = TRUE;
4747	midscreen(scr_vert, point);
4748}
4749
4750void
4751modes_op(void)
4752{
4753	int ret_value;
4754	int counter;
4755	char *string;
4756
4757	do
4758	{
4759		sprintf(modes_menu[1].item_string, "%s %s", mode_strings[1],
4760					(expand_tabs ? ON : OFF));
4761		sprintf(modes_menu[2].item_string, "%s %s", mode_strings[2],
4762					(case_sen ? ON : OFF));
4763		sprintf(modes_menu[3].item_string, "%s %s", mode_strings[3],
4764					(observ_margins ? ON : OFF));
4765		sprintf(modes_menu[4].item_string, "%s %s", mode_strings[4],
4766					(auto_format ? ON : OFF));
4767		sprintf(modes_menu[5].item_string, "%s %s", mode_strings[5],
4768					(eightbit ? ON : OFF));
4769		sprintf(modes_menu[6].item_string, "%s %s", mode_strings[6],
4770					(info_window ? ON : OFF));
4771		sprintf(modes_menu[7].item_string, "%s %s", mode_strings[7],
4772					(emacs_keys_mode ? ON : OFF));
4773		sprintf(modes_menu[8].item_string, "%s %d", mode_strings[8],
4774					right_margin);
4775		sprintf(modes_menu[9].item_string, "%s %s", mode_strings[9],
4776					(ee_chinese ? ON : OFF));
4777
4778		ret_value = menu_op(modes_menu);
4779
4780		switch (ret_value)
4781		{
4782			case 1:
4783				expand_tabs = !expand_tabs;
4784				break;
4785			case 2:
4786				case_sen = !case_sen;
4787				break;
4788			case 3:
4789				observ_margins = !observ_margins;
4790				break;
4791			case 4:
4792				auto_format = !auto_format;
4793				if (auto_format)
4794					observ_margins = TRUE;
4795				break;
4796			case 5:
4797				eightbit = !eightbit;
4798				if (!eightbit)
4799					ee_chinese = FALSE;
4800#ifdef NCURSE
4801				if (ee_chinese)
4802					nc_setattrib(A_NC_BIG5);
4803				else
4804					nc_clearattrib(A_NC_BIG5);
4805#endif /* NCURSE */
4806
4807				redraw();
4808				wnoutrefresh(text_win);
4809				break;
4810			case 6:
4811				if (info_window)
4812					no_info_window();
4813				else
4814					create_info_window();
4815				break;
4816			case 7:
4817				emacs_keys_mode = !emacs_keys_mode;
4818				if (info_window)
4819					paint_info_win();
4820				break;
4821			case 8:
4822				string = get_string(margin_prompt, TRUE);
4823				if (string != NULL)
4824				{
4825					counter = atoi(string);
4826					if (counter > 0)
4827						right_margin = counter;
4828					free(string);
4829				}
4830				break;
4831			case 9:
4832				ee_chinese = !ee_chinese;
4833				if (ee_chinese != FALSE)
4834					eightbit = TRUE;
4835#ifdef NCURSE
4836				if (ee_chinese)
4837					nc_setattrib(A_NC_BIG5);
4838				else
4839					nc_clearattrib(A_NC_BIG5);
4840#endif /* NCURSE */
4841				redraw();
4842				break;
4843			default:
4844				break;
4845		}
4846	}
4847	while (ret_value != 0);
4848}
4849
4850/* a strchr() look-alike for systems without strchr() */
4851char *
4852is_in_string(char *string, char *substring)
4853{
4854	char *full, *sub;
4855
4856	for (sub = substring; (sub != NULL) && (*sub != '\0'); sub++)
4857	{
4858		for (full = string; (full != NULL) && (*full != '\0');
4859				full++)
4860		{
4861			if (*sub == *full)
4862				return(full);
4863		}
4864	}
4865	return(NULL);
4866}
4867
4868/*
4869 |	handle names of the form "~/file", "~user/file",
4870 |	"$HOME/foo", "~/$FOO", etc.
4871 */
4872
4873char *
4874resolve_name(char *name)
4875{
4876	char long_buffer[1024];
4877	char short_buffer[128];
4878	char *buffer;
4879	char *slash;
4880	char *tmp;
4881	char *start_of_var;
4882	int offset;
4883	int index;
4884	int counter;
4885	struct passwd *user;
4886
4887	if (name[0] == '~')
4888	{
4889		if (name[1] == '/')
4890		{
4891			index = getuid();
4892			user = (struct passwd *) getpwuid(index);
4893			slash = name + 1;
4894		}
4895		else
4896		{
4897			slash = strchr(name, '/');
4898			if (slash == NULL)
4899				return(name);
4900			*slash = '\0';
4901			user = (struct passwd *) getpwnam((name + 1));
4902			*slash = '/';
4903		}
4904		if (user == NULL)
4905		{
4906			return(name);
4907		}
4908		buffer = malloc(strlen(user->pw_dir) + strlen(slash) + 1);
4909		strcpy(buffer, user->pw_dir);
4910		strcat(buffer, slash);
4911	}
4912	else
4913		buffer = name;
4914
4915	if (is_in_string(buffer, "$"))
4916	{
4917		tmp = buffer;
4918		index = 0;
4919
4920		while ((*tmp != '\0') && (index < 1024))
4921		{
4922
4923			while ((*tmp != '\0') && (*tmp != '$') &&
4924				(index < 1024))
4925			{
4926				long_buffer[index] = *tmp;
4927				tmp++;
4928				index++;
4929			}
4930
4931			if ((*tmp == '$') && (index < 1024))
4932			{
4933				counter = 0;
4934				start_of_var = tmp;
4935				tmp++;
4936				if (*tmp == '{') /* } */	/* bracketed variable name */
4937				{
4938					tmp++;				/* { */
4939					while ((*tmp != '\0') &&
4940						(*tmp != '}') &&
4941						(counter < 128))
4942					{
4943						short_buffer[counter] = *tmp;
4944						counter++;
4945						tmp++;
4946					}			/* { */
4947					if (*tmp == '}')
4948						tmp++;
4949				}
4950				else
4951				{
4952					while ((*tmp != '\0') &&
4953					       (*tmp != '/') &&
4954					       (*tmp != '$') &&
4955					       (counter < 128))
4956					{
4957						short_buffer[counter] = *tmp;
4958						counter++;
4959						tmp++;
4960					}
4961				}
4962				short_buffer[counter] = '\0';
4963				if ((slash = getenv(short_buffer)) != NULL)
4964				{
4965					offset = strlen(slash);
4966					if ((offset + index) < 1024)
4967						strcpy(&long_buffer[index], slash);
4968					index += offset;
4969				}
4970				else
4971				{
4972					while ((start_of_var != tmp) && (index < 1024))
4973					{
4974						long_buffer[index] = *start_of_var;
4975						start_of_var++;
4976						index++;
4977					}
4978				}
4979			}
4980		}
4981
4982		if (index == 1024)
4983			return(buffer);
4984		else
4985			long_buffer[index] = '\0';
4986
4987		if (name != buffer)
4988			free(buffer);
4989		buffer = malloc(index + 1);
4990		strcpy(buffer, long_buffer);
4991	}
4992
4993	return(buffer);
4994}
4995
4996int
4997restrict_mode(void)
4998{
4999	if (!restricted)
5000		return(FALSE);
5001
5002	wmove(com_win, 0, 0);
5003	wprintw(com_win, restricted_msg);
5004	wclrtoeol(com_win);
5005	wrefresh(com_win);
5006	clear_com_win = TRUE;
5007	return(TRUE);
5008}
5009
5010/*
5011 |	The following routine tests the input string against the list of
5012 |	strings, to determine if the string is a unique match with one of the
5013 |	valid values.
5014 */
5015
5016int
5017unique_test(char *string, char *list[])
5018{
5019	int counter;
5020	int num_match;
5021	int result;
5022
5023	num_match = 0;
5024	counter = 0;
5025	while (list[counter] != NULL)
5026	{
5027		result = compare(string, list[counter], FALSE);
5028		if (result)
5029			num_match++;
5030		counter++;
5031	}
5032	return(num_match);
5033}
5034
5035#ifndef NO_CATGETS
5036/*
5037 |	Get the catalog entry, and if it got it from the catalog,
5038 |	make a copy, since the buffer will be overwritten by the
5039 |	next call to catgets().
5040 */
5041
5042char *
5043catgetlocal(int number, char *string)
5044{
5045	char *temp1;
5046	char *temp2;
5047
5048	temp1 = catgets(catalog, 1, number, string);
5049	if (temp1 != string)
5050	{
5051		temp2 = malloc(strlen(temp1) + 1);
5052		strcpy(temp2, temp1);
5053		temp1 = temp2;
5054	}
5055	return(temp1);
5056}
5057#endif /* NO_CATGETS */
5058
5059/*
5060 |	The following is to allow for using message catalogs which allow
5061 |	the software to be 'localized', that is, to use different languages
5062 |	all with the same binary.  For more information, see your system
5063 |	documentation, or the X/Open Internationalization Guide.
5064 */
5065
5066void
5067strings_init(void)
5068{
5069	int counter;
5070
5071	setlocale(LC_ALL, "");
5072#ifndef NO_CATGETS
5073	catalog = catopen("ee", NL_CAT_LOCALE);
5074#endif /* NO_CATGETS */
5075
5076	modes_menu[0].item_string = catgetlocal( 1, "modes menu");
5077	mode_strings[1]  = catgetlocal( 2, "tabs to spaces       ");
5078	mode_strings[2]  = catgetlocal( 3, "case sensitive search");
5079	mode_strings[3]  = catgetlocal( 4, "margins observed     ");
5080	mode_strings[4]  = catgetlocal( 5, "auto-paragraph format");
5081	mode_strings[5]  = catgetlocal( 6, "eightbit characters  ");
5082	mode_strings[6]  = catgetlocal( 7, "info window          ");
5083	mode_strings[8]  = catgetlocal( 8, "right margin         ");
5084	leave_menu[0].item_string  = catgetlocal( 9, "leave menu");
5085	leave_menu[1].item_string  = catgetlocal( 10, "save changes");
5086	leave_menu[2].item_string  = catgetlocal( 11, "no save");
5087	file_menu[0].item_string  = catgetlocal( 12, "file menu");
5088	file_menu[1].item_string  = catgetlocal( 13, "read a file");
5089	file_menu[2].item_string  = catgetlocal( 14, "write a file");
5090	file_menu[3].item_string  = catgetlocal( 15, "save file");
5091	file_menu[4].item_string  = catgetlocal( 16, "print editor contents");
5092	search_menu[0].item_string = catgetlocal( 17, "search menu");
5093	search_menu[1].item_string = catgetlocal( 18, "search for ...");
5094	search_menu[2].item_string = catgetlocal( 19, "search");
5095	spell_menu[0].item_string = catgetlocal( 20, "spell menu");
5096	spell_menu[1].item_string = catgetlocal( 21, "use 'spell'");
5097	spell_menu[2].item_string = catgetlocal( 22, "use 'ispell'");
5098	misc_menu[0].item_string = catgetlocal( 23, "miscellaneous menu");
5099	misc_menu[1].item_string = catgetlocal( 24, "format paragraph");
5100	misc_menu[2].item_string = catgetlocal( 25, "shell command");
5101	misc_menu[3].item_string = catgetlocal( 26, "check spelling");
5102	main_menu[0].item_string  = catgetlocal( 27, "main menu");
5103	main_menu[1].item_string  = catgetlocal( 28, "leave editor");
5104	main_menu[2].item_string  = catgetlocal( 29, "help");
5105	main_menu[3].item_string  = catgetlocal( 30, "file operations");
5106	main_menu[4].item_string  = catgetlocal( 31, "redraw screen");
5107	main_menu[5].item_string  = catgetlocal( 32, "settings");
5108	main_menu[6].item_string  = catgetlocal( 33, "search");
5109	main_menu[7].item_string  = catgetlocal( 34, "miscellaneous");
5110	help_text[0] = catgetlocal( 35, "Control keys:                                                              ");
5111	help_text[1] = catgetlocal( 36, "^a ascii code           ^i tab                  ^r right                   ");
5112	help_text[2] = catgetlocal( 37, "^b bottom of text       ^j newline              ^t top of text             ");
5113	help_text[3] = catgetlocal( 38, "^c command              ^k delete char          ^u up                      ");
5114	help_text[4] = catgetlocal( 39, "^d down                 ^l left                 ^v undelete word           ");
5115	help_text[5] = catgetlocal( 40, "^e search prompt        ^m newline              ^w delete word             ");
5116	help_text[6] = catgetlocal( 41, "^f undelete char        ^n next page            ^x search                  ");
5117	help_text[7] = catgetlocal( 42, "^g begin of line        ^o end of line          ^y delete line             ");
5118	help_text[8] = catgetlocal( 43, "^h backspace            ^p prev page            ^z undelete line           ");
5119	help_text[9] = catgetlocal( 44, "^[ (escape) menu        ESC-Enter: exit ee                                 ");
5120	help_text[10] = catgetlocal( 45, "                                                                           ");
5121	help_text[11] = catgetlocal( 46, "Commands:                                                                  ");
5122	help_text[12] = catgetlocal( 47, "help    : get this info                 file    : print file name          ");
5123	help_text[13] = catgetlocal( 48, "read    : read a file                   char    : ascii code of char       ");
5124	help_text[14] = catgetlocal( 49, "write   : write a file                  case    : case sensitive search    ");
5125	help_text[15] = catgetlocal( 50, "exit    : leave and save                nocase  : case insensitive search  ");
5126	help_text[16] = catgetlocal( 51, "quit    : leave, no save                !cmd    : execute \"cmd\" in shell   ");
5127	help_text[17] = catgetlocal( 52, "line    : display line #                0-9     : go to line \"#\"           ");
5128	help_text[18] = catgetlocal( 53, "expand  : expand tabs                   noexpand: do not expand tabs         ");
5129	help_text[19] = catgetlocal( 54, "                                                                             ");
5130	help_text[20] = catgetlocal( 55, "  ee [+#] [-i] [-e] [-h] [file(s)]                                            ");
5131	help_text[21] = catgetlocal( 56, "+# :go to line #  -i :no info window  -e : don't expand tabs  -h :no highlight");
5132	control_keys[0] = catgetlocal( 57, "^[ (escape) menu  ^e search prompt  ^y delete line    ^u up     ^p prev page  ");
5133	control_keys[1] = catgetlocal( 58, "^a ascii code     ^x search         ^z undelete line  ^d down   ^n next page  ");
5134	control_keys[2] = catgetlocal( 59, "^b bottom of text ^g begin of line  ^w delete word    ^l left                 ");
5135	control_keys[3] = catgetlocal( 60, "^t top of text    ^o end of line    ^v undelete word  ^r right                ");
5136	control_keys[4] = catgetlocal( 61, "^c command        ^k delete char    ^f undelete char      ESC-Enter: exit ee  ");
5137	command_strings[0] = catgetlocal( 62, "help : get help info  |file  : print file name         |line : print line # ");
5138	command_strings[1] = catgetlocal( 63, "read : read a file    |char  : ascii code of char      |0-9 : go to line \"#\"");
5139	command_strings[2] = catgetlocal( 64, "write: write a file   |case  : case sensitive search   |exit : leave and save ");
5140	command_strings[3] = catgetlocal( 65, "!cmd : shell \"cmd\"    |nocase: ignore case in search   |quit : leave, no save");
5141	command_strings[4] = catgetlocal( 66, "expand: expand tabs   |noexpand: do not expand tabs                           ");
5142	com_win_message = catgetlocal( 67, "    press Escape (^[) for menu");
5143	no_file_string = catgetlocal( 68, "no file");
5144	ascii_code_str = catgetlocal( 69, "ascii code: ");
5145	printer_msg_str = catgetlocal( 70, "sending contents of buffer to \"%s\" ");
5146	command_str = catgetlocal( 71, "command: ");
5147	file_write_prompt_str = catgetlocal( 72, "name of file to write: ");
5148	file_read_prompt_str = catgetlocal( 73, "name of file to read: ");
5149	char_str = catgetlocal( 74, "character = %d");
5150	unkn_cmd_str = catgetlocal( 75, "unknown command \"%s\"");
5151	non_unique_cmd_msg = catgetlocal( 76, "entered command is not unique");
5152	line_num_str = catgetlocal( 77, "line %d  ");
5153	line_len_str = catgetlocal( 78, "length = %d");
5154	current_file_str = catgetlocal( 79, "current file is \"%s\" ");
5155	usage0 = catgetlocal( 80, "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n");
5156	usage1 = catgetlocal( 81, "       -i   turn off info window\n");
5157	usage2 = catgetlocal( 82, "       -e   do not convert tabs to spaces\n");
5158	usage3 = catgetlocal( 83, "       -h   do not use highlighting\n");
5159	file_is_dir_msg = catgetlocal( 84, "file \"%s\" is a directory");
5160	new_file_msg = catgetlocal( 85, "new file \"%s\"");
5161	cant_open_msg = catgetlocal( 86, "can't open \"%s\"");
5162	open_file_msg = catgetlocal( 87, "file \"%s\", %d lines");
5163	file_read_fin_msg = catgetlocal( 88, "finished reading file \"%s\"");
5164	reading_file_msg = catgetlocal( 89, "reading file \"%s\"");
5165	read_only_msg = catgetlocal( 90, ", read only");
5166	file_read_lines_msg = catgetlocal( 91, "file \"%s\", %d lines");
5167	save_file_name_prompt = catgetlocal( 92, "enter name of file: ");
5168	file_not_saved_msg = catgetlocal( 93, "no filename entered: file not saved");
5169	changes_made_prompt = catgetlocal( 94, "changes have been made, are you sure? (y/n [n]) ");
5170	yes_char = catgetlocal( 95, "y");
5171	file_exists_prompt = catgetlocal( 96, "file already exists, overwrite? (y/n) [n] ");
5172	create_file_fail_msg = catgetlocal( 97, "unable to create file \"%s\"");
5173	writing_file_msg = catgetlocal( 98, "writing file \"%s\"");
5174	file_written_msg = catgetlocal( 99, "\"%s\" %d lines, %d characters");
5175	searching_msg = catgetlocal( 100, "           ...searching");
5176	str_not_found_msg = catgetlocal( 101, "string \"%s\" not found");
5177	search_prompt_str = catgetlocal( 102, "search for: ");
5178	exec_err_msg = catgetlocal( 103, "could not exec %s\n");
5179	continue_msg = catgetlocal( 104, "press return to continue ");
5180	menu_cancel_msg = catgetlocal( 105, "press Esc to cancel");
5181	menu_size_err_msg = catgetlocal( 106, "menu too large for window");
5182	press_any_key_msg = catgetlocal( 107, "press any key to continue ");
5183	shell_prompt = catgetlocal( 108, "shell command: ");
5184	formatting_msg = catgetlocal( 109, "...formatting paragraph...");
5185	shell_echo_msg = catgetlocal( 110, "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-");
5186	spell_in_prog_msg = catgetlocal( 111, "sending contents of edit buffer to 'spell'");
5187	margin_prompt = catgetlocal( 112, "right margin is: ");
5188	restricted_msg = catgetlocal( 113, "restricted mode: unable to perform requested operation");
5189	ON = catgetlocal( 114, "ON");
5190	OFF = catgetlocal( 115, "OFF");
5191	HELP = catgetlocal( 116, "HELP");
5192	WRITE = catgetlocal( 117, "WRITE");
5193	READ = catgetlocal( 118, "READ");
5194	LINE = catgetlocal( 119, "LINE");
5195	FILE_str = catgetlocal( 120, "FILE");
5196	CHARACTER = catgetlocal( 121, "CHARACTER");
5197	REDRAW = catgetlocal( 122, "REDRAW");
5198	RESEQUENCE = catgetlocal( 123, "RESEQUENCE");
5199	AUTHOR = catgetlocal( 124, "AUTHOR");
5200	VERSION = catgetlocal( 125, "VERSION");
5201	CASE = catgetlocal( 126, "CASE");
5202	NOCASE = catgetlocal( 127, "NOCASE");
5203	EXPAND = catgetlocal( 128, "EXPAND");
5204	NOEXPAND = catgetlocal( 129, "NOEXPAND");
5205	Exit_string = catgetlocal( 130, "EXIT");
5206	QUIT_string = catgetlocal( 131, "QUIT");
5207	INFO = catgetlocal( 132, "INFO");
5208	NOINFO = catgetlocal( 133, "NOINFO");
5209	MARGINS = catgetlocal( 134, "MARGINS");
5210	NOMARGINS = catgetlocal( 135, "NOMARGINS");
5211	AUTOFORMAT = catgetlocal( 136, "AUTOFORMAT");
5212	NOAUTOFORMAT = catgetlocal( 137, "NOAUTOFORMAT");
5213	Echo = catgetlocal( 138, "ECHO");
5214	PRINTCOMMAND = catgetlocal( 139, "PRINTCOMMAND");
5215	RIGHTMARGIN = catgetlocal( 140, "RIGHTMARGIN");
5216	HIGHLIGHT = catgetlocal( 141, "HIGHLIGHT");
5217	NOHIGHLIGHT = catgetlocal( 142, "NOHIGHLIGHT");
5218	EIGHTBIT = catgetlocal( 143, "EIGHTBIT");
5219	NOEIGHTBIT = catgetlocal( 144, "NOEIGHTBIT");
5220	/*
5221	 |	additions
5222	 */
5223	mode_strings[7] = catgetlocal( 145, "emacs key bindings   ");
5224	emacs_help_text[0] = help_text[0];
5225	emacs_help_text[1] = catgetlocal( 146, "^a beginning of line    ^i tab                  ^r restore word            ");
5226	emacs_help_text[2] = catgetlocal( 147, "^b back 1 char          ^j undel char           ^t top of text             ");
5227	emacs_help_text[3] = catgetlocal( 148, "^c command              ^k delete line          ^u bottom of text          ");
5228	emacs_help_text[4] = catgetlocal( 149, "^d delete char          ^l undelete line        ^v next page               ");
5229	emacs_help_text[5] = catgetlocal( 150, "^e end of line          ^m newline              ^w delete word             ");
5230	emacs_help_text[6] = catgetlocal( 151, "^f forward 1 char       ^n next line            ^x search                  ");
5231	emacs_help_text[7] = catgetlocal( 152, "^g go back 1 page       ^o ascii char insert    ^y search prompt           ");
5232	emacs_help_text[8] = catgetlocal( 153, "^h backspace            ^p prev line            ^z next word               ");
5233	emacs_help_text[9] = help_text[9];
5234	emacs_help_text[10] = help_text[10];
5235	emacs_help_text[11] = help_text[11];
5236	emacs_help_text[12] = help_text[12];
5237	emacs_help_text[13] = help_text[13];
5238	emacs_help_text[14] = help_text[14];
5239	emacs_help_text[15] = help_text[15];
5240	emacs_help_text[16] = help_text[16];
5241	emacs_help_text[17] = help_text[17];
5242	emacs_help_text[18] = help_text[18];
5243	emacs_help_text[19] = help_text[19];
5244	emacs_help_text[20] = help_text[20];
5245	emacs_help_text[21] = help_text[21];
5246	emacs_control_keys[0] = catgetlocal( 154, "^[ (escape) menu ^y search prompt ^k delete line   ^p prev li     ^g prev page");
5247	emacs_control_keys[1] = catgetlocal( 155, "^o ascii code    ^x search        ^l undelete line ^n next li     ^v next page");
5248	emacs_control_keys[2] = catgetlocal( 156, "^u end of file   ^a begin of line ^w delete word   ^b back 1 char ^z next word");
5249	emacs_control_keys[3] = catgetlocal( 157, "^t top of text   ^e end of line   ^r restore word  ^f forward char            ");
5250	emacs_control_keys[4] = catgetlocal( 158, "^c command       ^d delete char   ^j undelete char              ESC-Enter: exit");
5251	EMACS_string = catgetlocal( 159, "EMACS");
5252	NOEMACS_string = catgetlocal( 160, "NOEMACS");
5253	usage4 = catgetlocal( 161, "       +#   put cursor at line #\n");
5254	conf_dump_err_msg = catgetlocal( 162, "unable to open .init.ee for writing, no configuration saved!");
5255	conf_dump_success_msg = catgetlocal( 163, "ee configuration saved in file %s");
5256	modes_menu[10].item_string = catgetlocal( 164, "save editor configuration");
5257	config_dump_menu[0].item_string = catgetlocal( 165, "save ee configuration");
5258	config_dump_menu[1].item_string = catgetlocal( 166, "save in current directory");
5259	config_dump_menu[2].item_string = catgetlocal( 167, "save in home directory");
5260	conf_not_saved_msg = catgetlocal( 168, "ee configuration not saved");
5261	ree_no_file_msg = catgetlocal( 169, "must specify a file when invoking ree");
5262	menu_too_lrg_msg = catgetlocal( 180, "menu too large for window");
5263	more_above_str = catgetlocal( 181, "^^more^^");
5264	more_below_str = catgetlocal( 182, "VVmoreVV");
5265	mode_strings[9] = catgetlocal( 183, "16 bit characters    ");
5266	chinese_cmd = catgetlocal( 184, "16BIT");
5267	nochinese_cmd = catgetlocal( 185, "NO16BIT");
5268
5269	commands[0] = HELP;
5270	commands[1] = WRITE;
5271	commands[2] = READ;
5272	commands[3] = LINE;
5273	commands[4] = FILE_str;
5274	commands[5] = REDRAW;
5275	commands[6] = RESEQUENCE;
5276	commands[7] = AUTHOR;
5277	commands[8] = VERSION;
5278	commands[9] = CASE;
5279	commands[10] = NOCASE;
5280	commands[11] = EXPAND;
5281	commands[12] = NOEXPAND;
5282	commands[13] = Exit_string;
5283	commands[14] = QUIT_string;
5284	commands[15] = "<";
5285	commands[16] = ">";
5286	commands[17] = "!";
5287	commands[18] = "0";
5288	commands[19] = "1";
5289	commands[20] = "2";
5290	commands[21] = "3";
5291	commands[22] = "4";
5292	commands[23] = "5";
5293	commands[24] = "6";
5294	commands[25] = "7";
5295	commands[26] = "8";
5296	commands[27] = "9";
5297	commands[28] = CHARACTER;
5298	commands[29] = chinese_cmd;
5299	commands[30] = nochinese_cmd;
5300	commands[31] = NULL;
5301	init_strings[0] = CASE;
5302	init_strings[1] = NOCASE;
5303	init_strings[2] = EXPAND;
5304	init_strings[3] = NOEXPAND;
5305	init_strings[4] = INFO;
5306	init_strings[5] = NOINFO;
5307	init_strings[6] = MARGINS;
5308	init_strings[7] = NOMARGINS;
5309	init_strings[8] = AUTOFORMAT;
5310	init_strings[9] = NOAUTOFORMAT;
5311	init_strings[10] = Echo;
5312	init_strings[11] = PRINTCOMMAND;
5313	init_strings[12] = RIGHTMARGIN;
5314	init_strings[13] = HIGHLIGHT;
5315	init_strings[14] = NOHIGHLIGHT;
5316	init_strings[15] = EIGHTBIT;
5317	init_strings[16] = NOEIGHTBIT;
5318	init_strings[17] = EMACS_string;
5319	init_strings[18] = NOEMACS_string;
5320	init_strings[19] = chinese_cmd;
5321	init_strings[20] = nochinese_cmd;
5322	init_strings[21] = NULL;
5323
5324	/*
5325	 |	allocate space for strings here for settings menu
5326	 */
5327
5328	for (counter = 1; counter < NUM_MODES_ITEMS; counter++)
5329	{
5330		modes_menu[counter].item_string = malloc(80);
5331	}
5332
5333#ifndef NO_CATGETS
5334	catclose(catalog);
5335#endif /* NO_CATGETS */
5336}
5337
5338