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