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