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