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