1 /**************************************************************************
2  *   nano.c  --  This file is part of GNU nano.                           *
3  *                                                                        *
4  *   Copyright (C) 1999-2011, 2013-2021 Free Software Foundation, Inc.    *
5  *   Copyright (C) 2014-2021 Benno Schulenberg                            *
6  *                                                                        *
7  *   GNU nano is free software: you can redistribute it and/or modify     *
8  *   it under the terms of the GNU General Public License as published    *
9  *   by the Free Software Foundation, either version 3 of the License,    *
10  *   or (at your option) any later version.                               *
11  *                                                                        *
12  *   GNU nano is distributed in the hope that it will be useful,          *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty          *
14  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.              *
15  *   See the GNU General Public License for more details.                 *
16  *                                                                        *
17  *   You should have received a copy of the GNU General Public License    *
18  *   along with this program.  If not, see http://www.gnu.org/licenses/.  *
19  *                                                                        *
20  **************************************************************************/
21 
22 #include "prototypes.h"
23 #include "revision.h"
24 
25 #include <ctype.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #if defined(__linux__) || !defined(NANO_TINY)
30 #include <sys/ioctl.h>
31 #endif
32 #ifdef ENABLE_UTF8
33 #include <langinfo.h>
34 #endif
35 #include <locale.h>
36 #include <string.h>
37 #ifdef HAVE_TERMIOS_H
38 #include <termios.h>
39 #endif
40 #include <unistd.h>
41 #ifdef __linux__
42 #include <sys/vt.h>
43 #endif
44 
45 #ifdef ENABLE_MULTIBUFFER
46 #define read_them_all  TRUE
47 #else
48 #define read_them_all  FALSE
49 #endif
50 
51 #ifdef ENABLE_MOUSE
52 static int oldinterval = -1;
53 		/* Used to store the user's original mouse click interval. */
54 #endif
55 #ifdef HAVE_TERMIOS_H
56 static struct termios original_state;
57 		/* The original settings of the user's terminal. */
58 #else
59 # define tcsetattr(...)
60 # define tcgetattr(...)
61 #endif
62 
63 static struct sigaction oldaction, newaction;
64 		/* Containers for the original and the temporary handler for SIGINT. */
65 
66 /* Create a new linestruct node.  Note that we do not set prevnode->next. */
make_new_node(linestruct * prevnode)67 linestruct *make_new_node(linestruct *prevnode)
68 {
69 	linestruct *newnode = nmalloc(sizeof(linestruct));
70 
71 	newnode->prev = prevnode;
72 	newnode->next = NULL;
73 	newnode->data = NULL;
74 #ifdef ENABLE_COLOR
75 	newnode->multidata = NULL;
76 #endif
77 	newnode->lineno = (prevnode) ? prevnode->lineno + 1 : 1;
78 #ifndef NANO_TINY
79 	newnode->has_anchor = FALSE;
80 #endif
81 
82 	return newnode;
83 }
84 
85 /* Splice a new node into an existing linked list of linestructs. */
splice_node(linestruct * afterthis,linestruct * newnode)86 void splice_node(linestruct *afterthis, linestruct *newnode)
87 {
88 	newnode->next = afterthis->next;
89 	newnode->prev = afterthis;
90 	if (afterthis->next != NULL)
91 		afterthis->next->prev = newnode;
92 	afterthis->next = newnode;
93 
94 	/* Update filebot when inserting a node at the end of file. */
95 	if (openfile && openfile->filebot == afterthis)
96 		openfile->filebot = newnode;
97 }
98 
99 /* Free the data structures in the given node. */
delete_node(linestruct * line)100 void delete_node(linestruct *line)
101 {
102 	/* If the first line on the screen gets deleted, step one back. */
103 	if (line == openfile->edittop)
104 		openfile->edittop = line->prev;
105 #ifdef ENABLE_WRAPPING
106 	/* If the spill-over line for hard-wrapping is deleted... */
107 	if (line == openfile->spillage_line)
108 		openfile->spillage_line = NULL;
109 #endif
110 	free(line->data);
111 #ifdef ENABLE_COLOR
112 	free(line->multidata);
113 #endif
114 	free(line);
115 }
116 
117 /* Disconnect a node from a linked list of linestructs and delete it. */
unlink_node(linestruct * line)118 void unlink_node(linestruct *line)
119 {
120 	if (line->prev != NULL)
121 		line->prev->next = line->next;
122 	if (line->next != NULL)
123 		line->next->prev = line->prev;
124 
125 	/* Update filebot when removing a node at the end of file. */
126 	if (openfile && openfile->filebot == line)
127 		openfile->filebot = line->prev;
128 
129 	delete_node(line);
130 }
131 
132 /* Free an entire linked list of linestructs. */
free_lines(linestruct * src)133 void free_lines(linestruct *src)
134 {
135 	if (src == NULL)
136 		return;
137 
138 	while (src->next != NULL) {
139 		src = src->next;
140 		delete_node(src->prev);
141 	}
142 
143 	delete_node(src);
144 }
145 
146 /* Make a copy of a linestruct node. */
copy_node(const linestruct * src)147 linestruct *copy_node(const linestruct *src)
148 {
149 	linestruct *dst = nmalloc(sizeof(linestruct));
150 
151 	dst->data = copy_of(src->data);
152 #ifdef ENABLE_COLOR
153 	dst->multidata = NULL;
154 #endif
155 	dst->lineno = src->lineno;
156 #ifndef NANO_TINY
157 	dst->has_anchor = src->has_anchor;
158 #endif
159 
160 	return dst;
161 }
162 
163 /* Duplicate an entire linked list of linestructs. */
copy_buffer(const linestruct * src)164 linestruct *copy_buffer(const linestruct *src)
165 {
166 	linestruct *head, *item;
167 
168 	head = copy_node(src);
169 	head->prev = NULL;
170 
171 	item = head;
172 	src = src->next;
173 
174 	while (src != NULL) {
175 		item->next = copy_node(src);
176 		item->next->prev = item;
177 
178 		item = item->next;
179 		src = src->next;
180 	}
181 
182 	item->next = NULL;
183 
184 	return head;
185 }
186 
187 /* Renumber the lines in a buffer, from the given line onwards. */
renumber_from(linestruct * line)188 void renumber_from(linestruct *line)
189 {
190 	ssize_t number = (line->prev == NULL) ? 0 : line->prev->lineno;
191 
192 	while (line != NULL) {
193 		line->lineno = ++number;
194 		line = line->next;
195 	}
196 }
197 
198 /* Display a warning about a key disabled in view mode. */
print_view_warning(void)199 void print_view_warning(void)
200 {
201 	statusline(AHEM, _("Key is invalid in view mode"));
202 }
203 
204 /* When in restricted mode, show a warning and return TRUE. */
in_restricted_mode(void)205 bool in_restricted_mode(void)
206 {
207 	if (ISSET(RESTRICTED)) {
208 		statusline(AHEM, _("This function is disabled in restricted mode"));
209 		beep();
210 		return TRUE;
211 	} else
212 		return FALSE;
213 }
214 
215 /* Make sure the cursor is visible, then exit from curses mode, disable
216  * bracketed-paste mode, and restore the original terminal settings. */
restore_terminal(void)217 void restore_terminal(void)
218 {
219 	curs_set(1);
220 	endwin();
221 #ifndef NANO_TINY
222 	printf("\x1B[?2004l");
223 	fflush(stdout);
224 #endif
225 	tcsetattr(STDIN_FILENO, TCSANOW, &original_state);
226 }
227 
228 /* Exit normally: restore terminal state and report any startup errors. */
finish(void)229 void finish(void)
230 {
231 	/* Blank the status bar and (if applicable) the shortcut list. */
232 	blank_statusbar();
233 	blank_bottombars();
234 	wrefresh(bottomwin);
235 
236 #ifndef NANO_TINY
237 	/* Deallocate the two or three subwindows. */
238 	if (topwin != NULL)
239 		delwin(topwin);
240 	delwin(edit);
241 	delwin(bottomwin);
242 #endif
243 	/* Switch the cursor on, exit from curses, and restore terminal settings. */
244 	restore_terminal();
245 
246 #if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
247 	display_rcfile_errors();
248 #endif
249 
250 	/* Get out. */
251 	exit(0);
252 }
253 
254 /* Close the current buffer, and terminate nano if it is the only buffer. */
close_and_go(void)255 void close_and_go(void)
256 {
257 #ifndef NANO_TINY
258 	if (openfile->lock_filename)
259 		delete_lockfile(openfile->lock_filename);
260 #endif
261 #ifdef ENABLE_HISTORIES
262 	if (ISSET(POSITIONLOG))
263 		update_poshistory();
264 #endif
265 #ifdef ENABLE_MULTIBUFFER
266 	/* If there is another buffer, close this one; otherwise just terminate. */
267 	if (openfile != openfile->next) {
268 		switch_to_next_buffer();
269 		openfile = openfile->prev;
270 		close_buffer();
271 		openfile = openfile->next;
272 		/* Adjust the count in the top bar. */
273 		titlebar(NULL);
274 	} else
275 #endif
276 	{
277 #ifdef ENABLE_HISTORIES
278 		if (ISSET(HISTORYLOG))
279 			save_history();
280 #endif
281 		finish();
282 	}
283 }
284 
285 /* Close the current buffer if it is unmodified; otherwise (when not doing
286  * automatic saving), ask the user whether to save it, then close it and
287  * exit, or return when the user cancelled. */
do_exit(void)288 void do_exit(void)
289 {
290 	int choice;
291 
292 	/* When unmodified, simply close.  Else, when doing automatic saving
293 	 * and the file has a name, simply save.  Otherwise, ask the user. */
294 	if (!openfile->modified)
295 		choice = 0;
296 	else if (ISSET(SAVE_ON_EXIT) && openfile->filename[0] != '\0')
297 		choice = 1;
298 	else {
299 		if (ISSET(SAVE_ON_EXIT))
300 			warn_and_briefly_pause(_("No file name"));
301 
302 		choice = do_yesno_prompt(FALSE, _("Save modified buffer? "));
303 	}
304 
305 	/* When not saving, or the save succeeds, close the buffer. */
306 	if (choice == 0 || (choice == 1 && do_writeout(TRUE, TRUE) > 0))
307 		close_and_go();
308 	else if (choice != 1)
309 		statusbar(_("Cancelled"));
310 }
311 
312 /* Save the current buffer under the given name (or "nano.<pid>" when nameless)
313  * with suffix ".save".  If needed, the name is further suffixed to be unique. */
emergency_save(const char * filename)314 void emergency_save(const char *filename)
315 {
316 	char *plainname, *targetname;
317 
318 	if (*filename == '\0') {
319 		plainname = nmalloc(28);
320 		sprintf(plainname, "nano.%u", getpid());
321 	} else
322 		plainname = copy_of(filename);
323 
324 	targetname = get_next_filename(plainname, ".save");
325 
326 	if (*targetname == '\0')
327 		fprintf(stderr, _("\nToo many .save files\n"));
328 	else if (write_file(targetname, NULL, SPECIAL, OVERWRITE, NONOTES)) {
329 		fprintf(stderr, _("\nBuffer written to %s\n"), targetname);
330 #ifndef NANO_TINY
331 		/* Try to chmod/chown the saved file to the values of the original file,
332 		 * but ignore any failure as we are in a hurry to get out. */
333 		if (openfile->statinfo) {
334 			IGNORE_CALL_RESULT(chmod(targetname, openfile->statinfo->st_mode));
335 			IGNORE_CALL_RESULT(chown(targetname, openfile->statinfo->st_uid,
336 													openfile->statinfo->st_gid));
337 		}
338 #endif
339 	}
340 
341 	free(targetname);
342 	free(plainname);
343 }
344 
345 /* Die gracefully -- by restoring the terminal state and saving any buffers
346  * that were modified. */
die(const char * msg,...)347 void die(const char *msg, ...)
348 {
349 	va_list ap;
350 	openfilestruct *firstone = openfile;
351 	static int stabs = 0;
352 
353 	/* When dying for a second time, just give up. */
354 	if (++stabs > 1)
355 		exit(11);
356 
357 	restore_terminal();
358 
359 #ifdef ENABLE_NANORC
360 	display_rcfile_errors();
361 #endif
362 
363 	/* Display the dying message. */
364 	va_start(ap, msg);
365 	vfprintf(stderr, msg, ap);
366 	va_end(ap);
367 
368 	while (openfile) {
369 #ifndef NANO_TINY
370 		/* If the current buffer has a lock file, remove it. */
371 		if (openfile->lock_filename)
372 			delete_lockfile(openfile->lock_filename);
373 #endif
374 		/* When modified, save the current buffer.  But not when in restricted
375 		 * mode, as it would write a file not mentioned on the command line. */
376 		if (openfile->modified && !ISSET(RESTRICTED))
377 			emergency_save(openfile->filename);
378 
379 #ifdef ENABLE_MULTIBUFFER
380 		openfile = openfile->next;
381 #endif
382 		if (openfile == firstone)
383 			break;
384 	}
385 
386 	/* Abandon the building. */
387 	exit(1);
388 }
389 
390 /* Initialize the three window portions nano uses. */
window_init(void)391 void window_init(void)
392 {
393 	/* When resizing, first delete the existing windows. */
394 	if (edit != NULL) {
395 		if (topwin != NULL)
396 			delwin(topwin);
397 		delwin(edit);
398 		delwin(bottomwin);
399 	}
400 
401 	topwin = NULL;
402 
403 	/* If the terminal is very flat, don't set up a title bar. */
404 	if (LINES < 3) {
405 		editwinrows = 1;
406 		/* Set up two subwindows.  If the terminal is just one line,
407 		 * edit window and status-bar window will cover each other. */
408 		edit = newwin(1, COLS, 0, 0);
409 		bottomwin = newwin(1, COLS, LINES - 1, 0);
410 	} else {
411 		int toprows = ((ISSET(EMPTY_LINE) && LINES > 5) ? 2 : 1);
412 		int bottomrows = ((ISSET(NO_HELP) || LINES < 5) ? 1 : 3);
413 
414 #ifndef NANO_TINY
415 		if (ISSET(MINIBAR))
416 			toprows = 0;
417 #endif
418 		editwinrows = LINES - toprows - bottomrows;
419 
420 		/* Set up the normal three subwindows. */
421 		if (toprows > 0)
422 			topwin = newwin(toprows, COLS, 0, 0);
423 		edit = newwin(editwinrows, COLS, toprows, 0);
424 		bottomwin = newwin(bottomrows, COLS, toprows + editwinrows, 0);
425 	}
426 
427 	/* In case the terminal shrunk, make sure the status line is clear. */
428 	wipe_statusbar();
429 
430 	/* When not disabled, turn escape-sequence translation on. */
431 	if (!ISSET(RAW_SEQUENCES)) {
432 		keypad(edit, TRUE);
433 		keypad(bottomwin, TRUE);
434 	}
435 
436 #ifdef ENABLED_WRAPORJUSTIFY
437 	/* Set up the wrapping point, accounting for screen width when negative. */
438 	if (COLS + fill < 0)
439 		wrap_at = 0;
440 	else if (fill <= 0)
441 		wrap_at = COLS + fill;
442 	else
443 		wrap_at = fill;
444 #endif
445 }
446 
447 #ifdef ENABLE_MOUSE
disable_mouse_support(void)448 void disable_mouse_support(void)
449 {
450 	mousemask(0, NULL);
451 	mouseinterval(oldinterval);
452 }
453 
enable_mouse_support(void)454 void enable_mouse_support(void)
455 {
456 	mousemask(ALL_MOUSE_EVENTS, NULL);
457 	oldinterval = mouseinterval(50);
458 }
459 
460 /* Switch mouse support on or off, as needed. */
mouse_init(void)461 void mouse_init(void)
462 {
463 	if (ISSET(USE_MOUSE))
464 		enable_mouse_support();
465 	else
466 		disable_mouse_support();
467 }
468 #endif /* ENABLE_MOUSE */
469 
470 /* Print the usage line for the given option to the screen. */
print_opt(const char * shortflag,const char * longflag,const char * desc)471 void print_opt(const char *shortflag, const char *longflag, const char *desc)
472 {
473 	int firstwidth = breadth(shortflag);
474 	int secondwidth = breadth(longflag);
475 
476 	printf(" %s", shortflag);
477 	if (firstwidth < 14)
478 		printf("%*s", 14 - firstwidth, " ");
479 
480 	printf(" %s", longflag);
481 	if (secondwidth < 24)
482 		printf("%*s", 24 - secondwidth, " ");
483 
484 	printf("%s\n", _(desc));
485 }
486 
487 /* Explain how to properly use nano and its command-line options. */
usage(void)488 void usage(void)
489 {
490 	printf(_("Usage: nano [OPTIONS] [[+LINE[,COLUMN]] FILE]...\n\n"));
491 #ifndef NANO_TINY
492 	/* TRANSLATORS: The next two strings are part of the --help output.
493 	 * It's best to keep its lines within 80 characters. */
494 	printf(_("To place the cursor on a specific line of a file, put the line number with\n"
495 				"a '+' before the filename.  The column number can be added after a comma.\n"));
496 	printf(_("When a filename is '-', nano reads data from standard input.\n\n"));
497 	/* TRANSLATORS: The next three are column headers of the --help output. */
498 	print_opt(_("Option"), _("Long option"), N_("Meaning"));
499 	/* TRANSLATORS: The next forty or so strings are option descriptions
500 	 * for the --help output.  Try to keep them at most 40 characters. */
501 	print_opt("-A", "--smarthome", N_("Enable smart home key"));
502 	if (!ISSET(RESTRICTED)) {
503 		print_opt("-B", "--backup", N_("Save backups of existing files"));
504 		print_opt(_("-C <dir>"), _("--backupdir=<dir>"),
505 					N_("Directory for saving unique backup files"));
506 	}
507 #endif
508 	print_opt("-D", "--boldtext", N_("Use bold instead of reverse video text"));
509 #ifndef NANO_TINY
510 	print_opt("-E", "--tabstospaces", N_("Convert typed tabs to spaces"));
511 #endif
512 #ifdef ENABLE_MULTIBUFFER
513 	if (!ISSET(RESTRICTED))
514 		print_opt("-F", "--multibuffer",
515 					N_("Read a file into a new buffer by default"));
516 #endif
517 #ifndef NANO_TINY
518 	print_opt("-G", "--locking", N_("Use (vim-style) lock files"));
519 #endif
520 #ifdef ENABLE_HISTORIES
521 	if (!ISSET(RESTRICTED))
522 		print_opt("-H", "--historylog",
523 					N_("Save & reload old search/replace strings"));
524 #endif
525 #ifdef ENABLE_NANORC
526 	print_opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
527 #endif
528 #ifndef NANO_TINY
529 	print_opt(_("-J <number>"), _("--guidestripe=<number>"),
530 					N_("Show a guiding bar at this column"));
531 #endif
532 	print_opt("-K", "--rawsequences",
533 					N_("Fix numeric keypad key confusion problem"));
534 #ifndef NANO_TINY
535 	print_opt("-L", "--nonewlines",
536 					N_("Don't add an automatic newline"));
537 #endif
538 #ifdef ENABLED_WRAPORJUSTIFY
539 	print_opt("-M", "--trimblanks",
540 					N_("Trim tail spaces when hard-wrapping"));
541 #endif
542 #ifndef NANO_TINY
543 	print_opt("-N", "--noconvert",
544 					N_("Don't convert files from DOS/Mac format"));
545 	print_opt("-O", "--bookstyle",
546 					N_("Leading whitespace means new paragraph"));
547 #endif
548 #ifdef ENABLE_HISTORIES
549 	if (!ISSET(RESTRICTED))
550 		print_opt("-P", "--positionlog",
551 					N_("Save & restore position of the cursor"));
552 #endif
553 #ifdef ENABLE_JUSTIFY
554 	print_opt(_("-Q <regex>"), _("--quotestr=<regex>"),
555 					/* TRANSLATORS: This refers to email quoting,
556 					 * like the > in: > quoted text. */
557 					N_("Regular expression to match quoting"));
558 #endif
559 	if (!ISSET(RESTRICTED))
560 		print_opt("-R", "--restricted", N_("Restrict access to the filesystem"));
561 #ifndef NANO_TINY
562 	print_opt("-S", "--softwrap", N_("Display overlong lines on multiple rows"));
563 	print_opt(_("-T <number>"), _("--tabsize=<number>"),
564 					N_("Make a tab this number of columns wide"));
565 #endif
566 	print_opt("-U", "--quickblank", N_("Wipe status bar upon next keystroke"));
567 	print_opt("-V", "--version", N_("Print version information and exit"));
568 #ifndef NANO_TINY
569 	print_opt("-W", "--wordbounds",
570 					N_("Detect word boundaries more accurately"));
571 	print_opt(_("-X <string>"), _("--wordchars=<string>"),
572 					N_("Which other characters are word parts"));
573 #endif
574 #ifdef ENABLE_COLOR
575 	if (!ISSET(RESTRICTED))
576 		print_opt(_("-Y <name>"), _("--syntax=<name>"),
577 					N_("Syntax definition to use for coloring"));
578 #endif
579 #ifndef NANO_TINY
580 	print_opt("-Z", "--zap", N_("Let Bsp and Del erase a marked region"));
581 	print_opt("-a", "--atblanks", N_("When soft-wrapping, do it at whitespace"));
582 #endif
583 #ifdef ENABLE_WRAPPING
584 	print_opt("-b", "--breaklonglines", N_("Automatically hard-wrap overlong lines"));
585 #endif
586 	print_opt("-c", "--constantshow", N_("Constantly show cursor position"));
587 	print_opt("-d", "--rebinddelete",
588 					N_("Fix Backspace/Delete confusion problem"));
589 #ifndef NANO_TINY
590 	print_opt("-e", "--emptyline", N_("Keep the line below the title bar empty"));
591 #endif
592 #ifdef ENABLE_NANORC
593 	print_opt(_("-f <file>"), _("--rcfile=<file>"),
594 					N_("Use only this file for configuring nano"));
595 #endif
596 #if defined(ENABLE_BROWSER) || defined(ENABLE_HELP)
597 	print_opt("-g", "--showcursor", N_("Show cursor in file browser & help text"));
598 #endif
599 	print_opt("-h", "--help", N_("Show this help text and exit"));
600 #ifndef NANO_TINY
601 	print_opt("-i", "--autoindent", N_("Automatically indent new lines"));
602 	print_opt("-j", "--jumpyscrolling", N_("Scroll per half-screen, not per line"));
603 	print_opt("-k", "--cutfromcursor", N_("Cut from cursor to end of line"));
604 #endif
605 #ifdef ENABLE_LINENUMBERS
606 	print_opt("-l", "--linenumbers", N_("Show line numbers in front of the text"));
607 #endif
608 #ifdef ENABLE_MOUSE
609 	print_opt("-m", "--mouse", N_("Enable the use of the mouse"));
610 #endif
611 #ifndef NANO_TINY
612 	print_opt("-n", "--noread", N_("Do not read the file (only write it)"));
613 #endif
614 #ifdef ENABLE_OPERATINGDIR
615 	print_opt(_("-o <dir>"), _("--operatingdir=<dir>"),
616 					N_("Set operating directory"));
617 #endif
618 	print_opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
619 #ifndef NANO_TINY
620 	print_opt("-q", "--indicator", N_("Show a position+portion indicator"));
621 #endif
622 #ifdef ENABLED_WRAPORJUSTIFY
623 	print_opt(_("-r <number>"), _("--fill=<number>"),
624 					N_("Set width for hard-wrap and justify"));
625 #endif
626 #ifdef ENABLE_SPELLER
627 	if (!ISSET(RESTRICTED))
628 		print_opt(_("-s <program>"), _("--speller=<program>"),
629 					N_("Use this alternative spell checker"));
630 #endif
631 	print_opt("-t", "--saveonexit", N_("Save changes on exit, don't prompt"));
632 #ifndef NANO_TINY
633 	print_opt("-u", "--unix", N_("Save a file by default in Unix format"));
634 #endif
635 	print_opt("-v", "--view", N_("View mode (read-only)"));
636 #ifdef ENABLE_WRAPPING
637 	print_opt("-w", "--nowrap", N_("Don't hard-wrap long lines [default]"));
638 #endif
639 	print_opt("-x", "--nohelp", N_("Don't show the two help lines"));
640 #ifndef NANO_TINY
641 	print_opt("-y", "--afterends", N_("Make Ctrl+Right stop at word ends"));
642 #endif
643 	if (!ISSET(RESTRICTED))
644 		print_opt("-z", "--suspendable", N_("Enable suspension"));
645 #ifndef NANO_TINY
646 	print_opt("-%", "--stateflags", N_("Show some states on the title bar"));
647 	print_opt("-_", "--minibar", N_("Show a feedback bar at the bottom"));
648 #endif
649 #ifdef HAVE_LIBMAGIC
650 	print_opt("-!", "--magic", N_("Also try magic to determine syntax"));
651 #endif
652 }
653 
654 /* Display the version number of this nano, a copyright notice, some contact
655  * information, and the configuration options this nano was compiled with. */
version(void)656 void version(void)
657 {
658 #ifdef REVISION
659 	printf(" GNU nano from git, %s\n", REVISION);
660 #else
661 	printf(_(" GNU nano, version %s\n"), VERSION);
662 #endif
663 #ifndef NANO_TINY
664 	printf(" (C) 1999-2011, 2013-2021 Free Software Foundation, Inc.\n");
665 	printf(_(" (C) 2014-%s the contributors to nano\n"), "2021");
666 #endif
667 	printf(_(" Compiled options:"));
668 
669 #ifdef NANO_TINY
670 	printf(" --enable-tiny");
671 #ifdef ENABLE_BROWSER
672 	printf(" --enable-browser");
673 #endif
674 #ifdef ENABLE_COLOR
675 	printf(" --enable-color");
676 #endif
677 #ifdef ENABLE_EXTRA
678 	printf(" --enable-extra");
679 #endif
680 #ifdef ENABLE_HELP
681 	printf(" --enable-help");
682 #endif
683 #ifdef ENABLE_HISTORIES
684 	printf(" --enable-histories");
685 #endif
686 #ifdef ENABLE_JUSTIFY
687 	printf(" --enable-justify");
688 #endif
689 #ifdef HAVE_LIBMAGIC
690 	printf(" --enable-libmagic");
691 #endif
692 #ifdef ENABLE_LINENUMBERS
693 	printf(" --enable-linenumbers");
694 #endif
695 #ifdef ENABLE_MOUSE
696 	printf(" --enable-mouse");
697 #endif
698 #ifdef ENABLE_NANORC
699 	printf(" --enable-nanorc");
700 #endif
701 #ifdef ENABLE_MULTIBUFFER
702 	printf(" --enable-multibuffer");
703 #endif
704 #ifdef ENABLE_OPERATINGDIR
705 	printf(" --enable-operatingdir");
706 #endif
707 #ifdef ENABLE_SPELLER
708 	printf(" --enable-speller");
709 #endif
710 #ifdef ENABLE_TABCOMP
711 	printf(" --enable-tabcomp");
712 #endif
713 #ifdef ENABLE_WRAPPING
714 	printf(" --enable-wrapping");
715 #endif
716 #else /* !NANO_TINY */
717 #ifndef ENABLE_BROWSER
718 	printf(" --disable-browser");
719 #endif
720 #ifndef ENABLE_COLOR
721 	printf(" --disable-color");
722 #endif
723 #ifndef ENABLE_COMMENT
724 	printf(" --disable-comment");
725 #endif
726 #ifndef ENABLE_EXTRA
727 	printf(" --disable-extra");
728 #endif
729 #ifndef ENABLE_HELP
730 	printf(" --disable-help");
731 #endif
732 #ifndef ENABLE_HISTORIES
733 	printf(" --disable-histories");
734 #endif
735 #ifndef ENABLE_JUSTIFY
736 	printf(" --disable-justify");
737 #endif
738 #ifndef HAVE_LIBMAGIC
739 	printf(" --disable-libmagic");
740 #endif
741 #ifndef ENABLE_LINENUMBERS
742 	printf(" --disable-linenumbers");
743 #endif
744 #ifndef ENABLE_MOUSE
745 	printf(" --disable-mouse");
746 #endif
747 #ifndef ENABLE_MULTIBUFFER
748 	printf(" --disable-multibuffer");
749 #endif
750 #ifndef ENABLE_NANORC
751 	printf(" --disable-nanorc");
752 #endif
753 #ifndef ENABLE_OPERATINGDIR
754 	printf(" --disable-operatingdir");
755 #endif
756 #ifndef ENABLE_SPELLER
757 	printf(" --disable-speller");
758 #endif
759 #ifndef ENABLE_TABCOMP
760 	printf(" --disable-tabcomp");
761 #endif
762 #ifndef ENABLE_WORDCOMPLETION
763 	printf(" --disable-wordcomp");
764 #endif
765 #ifndef ENABLE_WRAPPING
766 	printf(" --disable-wrapping");
767 #endif
768 #endif /* !NANO_TINY */
769 
770 #ifdef DEBUG
771 	printf(" --enable-debug");
772 #endif
773 #ifndef ENABLE_NLS
774 	printf(" --disable-nls");
775 #endif
776 #ifdef ENABLE_UTF8
777 	printf(" --enable-utf8");
778 #else
779 	printf(" --disable-utf8");
780 #endif
781 	printf("\n");
782 }
783 
784 /* Register that Ctrl+C was pressed during some system call. */
make_a_note(int signal)785 void make_a_note(int signal)
786 {
787 	control_C_was_pressed = TRUE;
788 }
789 
790 /* Make ^C interrupt a system call and set a flag. */
install_handler_for_Ctrl_C(void)791 void install_handler_for_Ctrl_C(void)
792 {
793 	/* Enable the generation of a SIGINT when ^C is pressed. */
794 	enable_kb_interrupt();
795 
796 	/* Set up a signal handler so that pressing ^C will set a flag. */
797 	newaction.sa_handler = make_a_note;
798 	newaction.sa_flags = 0;
799 	sigaction(SIGINT, &newaction, &oldaction);
800 }
801 
802 /* Go back to ignoring ^C. */
restore_handler_for_Ctrl_C(void)803 void restore_handler_for_Ctrl_C(void)
804 {
805 	sigaction(SIGINT, &oldaction, NULL);
806 	disable_kb_interrupt();
807 }
808 
809 #ifndef NANO_TINY
810 /* Reconnect standard input to the tty, and store its state. */
reconnect_and_store_state(void)811 void reconnect_and_store_state(void)
812 {
813 	int thetty = open("/dev/tty", O_RDONLY);
814 
815 	if (thetty < 0 || dup2(thetty, STDIN_FILENO) < 0)
816 		die(_("Could not reconnect stdin to keyboard\n"));
817 
818 	close(thetty);
819 
820 	/* If input was not cut short, store the current state of the terminal. */
821 	if (!control_C_was_pressed)
822 		tcgetattr(STDIN_FILENO, &original_state);
823 }
824 
825 /* Read whatever comes from standard input into a new buffer. */
scoop_stdin(void)826 bool scoop_stdin(void)
827 {
828 	FILE *stream;
829 
830 	restore_terminal();
831 
832 	/* When input comes from a terminal, show a helpful message. */
833 	if (isatty(STDIN_FILENO))
834 		fprintf(stderr, _("Reading data from keyboard; "
835 							"type ^D or ^D^D to finish.\n"));
836 
837 	/* Open standard input. */
838 	stream = fopen("/dev/stdin", "rb");
839 	if (stream == NULL) {
840 		int errnumber = errno;
841 
842 		terminal_init();
843 		doupdate();
844 		statusline(ALERT, _("Failed to open stdin: %s"), strerror(errnumber));
845 		return FALSE;
846 	}
847 
848 	/* Set up a signal handler so that ^C will stop the reading. */
849 	install_handler_for_Ctrl_C();
850 
851 	/* Read the input into a new buffer. */
852 	make_new_buffer();
853 	read_file(stream, 0, "stdin", TRUE);
854 #ifdef ENABLE_COLOR
855 	find_and_prime_applicable_syntax();
856 #endif
857 
858 	/* Restore the original ^C handler. */
859 	restore_handler_for_Ctrl_C();
860 
861 	if (!ISSET(VIEW_MODE) && openfile->totsize > 0)
862 		set_modified();
863 
864 	return TRUE;
865 }
866 #endif
867 
868 /* Register half a dozen signal handlers. */
signal_init(void)869 void signal_init(void)
870 {
871 	struct sigaction deed = {{0}};
872 
873 	/* Trap SIGINT and SIGQUIT because we want them to do useful things. */
874 	deed.sa_handler = SIG_IGN;
875 	sigaction(SIGINT, &deed, NULL);
876 #ifdef SIGQUIT
877 	sigaction(SIGQUIT, &deed, NULL);
878 #endif
879 
880 	/* Trap SIGHUP and SIGTERM because we want to write the file out. */
881 	deed.sa_handler = handle_hupterm;
882 #ifdef SIGHUP
883 	sigaction(SIGHUP, &deed, NULL);
884 #endif
885 	sigaction(SIGTERM, &deed, NULL);
886 
887 #ifndef NANO_TINY
888 	/* Trap SIGWINCH because we want to handle window resizes. */
889 	deed.sa_handler = handle_sigwinch;
890 	sigaction(SIGWINCH, &deed, NULL);
891 #endif
892 
893 	/* In the suspend and continue handlers, block all other signals.
894 	 * If we don't do this, other stuff interrupts them! */
895 	sigfillset(&deed.sa_mask);
896 #ifdef SIGTSTP
897 	deed.sa_handler = do_suspend;
898 	sigaction(SIGTSTP, &deed, NULL);
899 #endif
900 #ifdef SIGCONT
901 	deed.sa_handler = do_continue;
902 	sigaction(SIGCONT, &deed, NULL);
903 #endif
904 
905 #if !defined(NANO_TINY) && !defined(DEBUG)
906 	if (getenv("NANO_NOCATCH") == NULL) {
907 		/* Trap SIGSEGV and SIGABRT to save any changed buffers and reset
908 		 * the terminal to a usable state.  Reset these handlers to their
909 		 * defaults as soon as their signal fires. */
910 		deed.sa_handler = handle_crash;
911 		deed.sa_flags |= SA_RESETHAND;
912 		sigaction(SIGSEGV, &deed, NULL);
913 		sigaction(SIGABRT, &deed, NULL);
914 	}
915 #endif
916 }
917 
918 /* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
handle_hupterm(int signal)919 void handle_hupterm(int signal)
920 {
921 	die(_("Received SIGHUP or SIGTERM\n"));
922 }
923 
924 #if !defined(NANO_TINY) && !defined(DEBUG)
925 /* Handler for SIGSEGV (segfault) and SIGABRT (abort). */
handle_crash(int signal)926 void handle_crash(int signal)
927 {
928 	die(_("Sorry! Nano crashed!  Code: %d.  Please report a bug.\n"), signal);
929 }
930 #endif
931 
932 /* Handler for SIGTSTP (suspend). */
do_suspend(int signal)933 void do_suspend(int signal)
934 {
935 #ifdef ENABLE_MOUSE
936 	disable_mouse_support();
937 #endif
938 	restore_terminal();
939 
940 	printf("\n\n");
941 
942 	/* Display our helpful message. */
943 	printf(_("Use \"fg\" to return to nano.\n"));
944 	fflush(stdout);
945 
946 	/* The suspend keystroke must not elicit cursor-position display. */
947 	lastmessage = HUSH;
948 
949 #ifdef SIGSTOP
950 	/* Do what mutt does: send ourselves a SIGSTOP. */
951 	kill(0, SIGSTOP);
952 #endif
953 }
954 
955 /* Put nano to sleep (if suspension is enabled). */
do_suspend_void(void)956 void do_suspend_void(void)
957 {
958 	if (!ISSET(SUSPENDABLE)) {
959 		statusline(AHEM, _("Suspension is not enabled"));
960 		beep();
961 	} else
962 		do_suspend(0);
963 
964 	ran_a_tool = TRUE;
965 }
966 
967 /* Handler for SIGCONT (continue after suspend). */
do_continue(int signal)968 void do_continue(int signal)
969 {
970 #ifdef ENABLE_MOUSE
971 	if (ISSET(USE_MOUSE))
972 		enable_mouse_support();
973 #endif
974 
975 #ifndef NANO_TINY
976 	/* Perhaps the user resized the window while we slept. */
977 	the_window_resized = TRUE;
978 #else
979 	/* Put the terminal in the desired state again. */
980 	terminal_init();
981 #endif
982 
983 	/* Insert a fake keystroke, to neutralize a key-eating issue. */
984 	ungetch(KEY_FLUSH);
985 }
986 
987 #if !defined(NANO_TINY) || defined(ENABLE_SPELLER) || defined(ENABLE_COLOR)
988 /* Block or unblock the SIGWINCH signal, depending on the blockit parameter. */
block_sigwinch(bool blockit)989 void block_sigwinch(bool blockit)
990 {
991 	sigset_t winch;
992 
993 	sigemptyset(&winch);
994 	sigaddset(&winch, SIGWINCH);
995 	sigprocmask(blockit ? SIG_BLOCK : SIG_UNBLOCK, &winch, NULL);
996 
997 #ifndef NANO_TINY
998 	if (the_window_resized)
999 		regenerate_screen();
1000 #endif
1001 }
1002 #endif
1003 
1004 #ifndef NANO_TINY
1005 /* Handler for SIGWINCH (window size change). */
handle_sigwinch(int signal)1006 void handle_sigwinch(int signal)
1007 {
1008 	/* Let the input routine know that a SIGWINCH has occurred. */
1009 	the_window_resized = TRUE;
1010 }
1011 
1012 /* Reinitialize and redraw the screen completely. */
regenerate_screen(void)1013 void regenerate_screen(void)
1014 {
1015 	const char *tty = ttyname(0);
1016 	int fd, result = 0;
1017 	struct winsize win;
1018 
1019 	/* Reset the trigger. */
1020 	the_window_resized = FALSE;
1021 
1022 	if (tty == NULL)
1023 		return;
1024 	fd = open(tty, O_RDWR);
1025 	if (fd == -1)
1026 		return;
1027 	result = ioctl(fd, TIOCGWINSZ, &win);
1028 	close(fd);
1029 	if (result == -1)
1030 		return;
1031 
1032 	/* We could check whether COLS or LINES changed, and return otherwise,
1033 	 * but it seems curses does not always update these global variables. */
1034 #ifdef REDEFINING_MACROS_OK
1035 	COLS = win.ws_col;
1036 	LINES = win.ws_row;
1037 #endif
1038 	thebar = (ISSET(INDICATOR) && LINES > 5 && COLS > 9) ? 1 : 0;
1039 	bardata = nrealloc(bardata, LINES * sizeof(int));
1040 
1041 	editwincols = COLS - margin - thebar;
1042 
1043 	/* Do as the website suggests: leave and immediately reenter curses mode. */
1044 	endwin();
1045 	doupdate();
1046 
1047 	/* Put the terminal in the desired state again, and
1048 	 * recreate the subwindows with their (new) sizes. */
1049 	terminal_init();
1050 	window_init();
1051 
1052 	/* If we have an open buffer, redraw the contents of the subwindows. */
1053 	if (openfile) {
1054 		ensure_firstcolumn_is_aligned();
1055 		draw_all_subwindows();
1056 	}
1057 }
1058 
1059 /* Handle the global toggle specified in flag. */
do_toggle(int flag)1060 void do_toggle(int flag)
1061 {
1062 	if (flag == SUSPENDABLE && in_restricted_mode())
1063 		return;
1064 
1065 	TOGGLE(flag);
1066 	focusing = FALSE;
1067 
1068 	switch (flag) {
1069 		case NO_HELP:
1070 			window_init();
1071 			draw_all_subwindows();
1072 			break;
1073 #ifdef ENABLE_MOUSE
1074 		case USE_MOUSE:
1075 			mouse_init();
1076 			break;
1077 #endif
1078 		case SOFTWRAP:
1079 			if (!ISSET(SOFTWRAP))
1080 				openfile->firstcolumn = 0;
1081 			refresh_needed = TRUE;
1082 			break;
1083 		case WHITESPACE_DISPLAY:
1084 			titlebar(NULL);
1085 			refresh_needed = TRUE;
1086 			break;
1087 #ifdef ENABLE_COLOR
1088 		case NO_SYNTAX:
1089 			precalc_multicolorinfo();
1090 			refresh_needed = TRUE;
1091 			break;
1092 #endif
1093 	}
1094 
1095 	if (!ISSET(MINIBAR) && ISSET(STATEFLAGS))
1096 		if (flag == AUTOINDENT || flag == BREAK_LONG_LINES || flag == SOFTWRAP)
1097 			titlebar(NULL);
1098 
1099 	if (ISSET(MINIBAR) && (flag == NO_HELP || flag == LINE_NUMBERS))
1100 		return;
1101 
1102 	if (flag == CONSTANT_SHOW)
1103 		wipe_statusbar();
1104 	else if (!ISSET(MINIBAR) || !ISSET(STATEFLAGS) || flag == SMART_HOME ||
1105 						flag == NO_SYNTAX || flag == WHITESPACE_DISPLAY ||
1106 						flag == CUT_FROM_CURSOR || flag == TABS_TO_SPACES ||
1107 						flag == USE_MOUSE || flag == SUSPENDABLE) {
1108 		bool enabled = ISSET(flag);
1109 
1110 		if (flag == NO_HELP || flag == NO_SYNTAX)
1111 			enabled = !enabled;
1112 
1113 		statusline(REMARK, "%s %s", _(flagtostr(flag)),
1114 									enabled ? _("enabled") : _("disabled"));
1115 	}
1116 }
1117 #endif /* !NANO_TINY */
1118 
1119 /* Disable extended input and output processing in our terminal settings. */
disable_extended_io(void)1120 void disable_extended_io(void)
1121 {
1122 #ifdef HAVE_TERMIOS_H
1123 	struct termios settings = {0};
1124 
1125 	tcgetattr(0, &settings);
1126 	settings.c_lflag &= ~IEXTEN;
1127 	settings.c_oflag &= ~OPOST;
1128 	tcsetattr(0, TCSANOW, &settings);
1129 #endif
1130 }
1131 
1132 /* Stop ^C from generating a SIGINT. */
disable_kb_interrupt(void)1133 void disable_kb_interrupt(void)
1134 {
1135 #ifdef HAVE_TERMIOS_H
1136 	struct termios settings = {0};
1137 
1138 	tcgetattr(0, &settings);
1139 	settings.c_lflag &= ~ISIG;
1140 	tcsetattr(0, TCSANOW, &settings);
1141 #endif
1142 }
1143 
1144 /* Make ^C generate a SIGINT. */
enable_kb_interrupt(void)1145 void enable_kb_interrupt(void)
1146 {
1147 #ifdef HAVE_TERMIOS_H
1148 	struct termios settings = {0};
1149 
1150 	tcgetattr(0, &settings);
1151 	settings.c_lflag |= ISIG;
1152 	tcsetattr(0, TCSANOW, &settings);
1153 #endif
1154 }
1155 
1156 /* Disable the terminal's XON/XOFF flow-control characters. */
disable_flow_control(void)1157 void disable_flow_control(void)
1158 {
1159 #ifdef HAVE_TERMIOS_H
1160 	struct termios settings;
1161 
1162 	tcgetattr(0, &settings);
1163 	settings.c_iflag &= ~IXON;
1164 	tcsetattr(0, TCSANOW, &settings);
1165 #endif
1166 }
1167 
1168 /* Enable the terminal's XON/XOFF flow-control characters. */
enable_flow_control(void)1169 void enable_flow_control(void)
1170 {
1171 #ifdef HAVE_TERMIOS_H
1172 	struct termios settings;
1173 
1174 	tcgetattr(0, &settings);
1175 	settings.c_iflag |= IXON;
1176 	tcsetattr(0, TCSANOW, &settings);
1177 #endif
1178 }
1179 
1180 /* Set up the terminal state.  Put the terminal in raw mode (read one
1181  * character at a time, disable the special control keys, and disable
1182  * the flow control characters), disable translation of carriage return
1183  * (^M) into newline (^J) so that we can tell the difference between the
1184  * Enter key and Ctrl-J, and disable echoing of characters as they're
1185  * typed.  Finally, disable extended input and output processing, and,
1186  * if we're not in preserve mode, reenable interpretation of the flow
1187  * control characters. */
terminal_init(void)1188 void terminal_init(void)
1189 {
1190 	raw();
1191 	nonl();
1192 	noecho();
1193 
1194 	disable_extended_io();
1195 
1196 	if (ISSET(PRESERVE))
1197 		enable_flow_control();
1198 
1199 	disable_kb_interrupt();
1200 
1201 #ifndef NANO_TINY
1202 	/* Tell the terminal to enable bracketed pastes. */
1203 	printf("\x1B[?2004h");
1204 	fflush(stdout);
1205 #endif
1206 }
1207 
1208 /* Ask ncurses for a keycode, or assign a default one. */
get_keycode(const char * keyname,const int standard)1209 int get_keycode(const char *keyname, const int standard)
1210 {
1211 #ifdef HAVE_KEY_DEFINED
1212 	const char *keyvalue = tigetstr(keyname);
1213 
1214 	if (keyvalue != 0 && keyvalue != (char *)-1 && key_defined(keyvalue))
1215 		return key_defined(keyvalue);
1216 #endif
1217 #ifdef DEBUG
1218 	if (!ISSET(RAW_SEQUENCES))
1219 		fprintf(stderr, "Using fallback keycode for %s\n", keyname);
1220 #endif
1221 	return standard;
1222 }
1223 
1224 #ifdef ENABLE_LINENUMBERS
1225 /* Ensure that the margin can accommodate the buffer's highest line number. */
confirm_margin(void)1226 void confirm_margin(void)
1227 {
1228 	int needed_margin = digits(openfile->filebot->lineno) + 1;
1229 
1230 	/* When not requested or space is too tight, suppress line numbers. */
1231 	if (!ISSET(LINE_NUMBERS) || needed_margin > COLS - 4)
1232 		needed_margin = 0;
1233 
1234 	if (needed_margin != margin) {
1235 		bool keep_focus = (margin > 0) && focusing;
1236 
1237 		margin = needed_margin;
1238 		editwincols = COLS - margin - thebar;
1239 
1240 #ifndef NANO_TINY
1241 		/* Ensure a proper starting column for the first screen row. */
1242 		ensure_firstcolumn_is_aligned();
1243 		focusing = keep_focus;
1244 #endif
1245 		/* The margin has changed -- schedule a full refresh. */
1246 		refresh_needed = TRUE;
1247 	}
1248 }
1249 #endif /* ENABLE_LINENUMBERS */
1250 
1251 /* Say that an unbound key was struck, and if possible which one. */
unbound_key(int code)1252 void unbound_key(int code)
1253 {
1254 	if (code == FOREIGN_SEQUENCE)
1255 		/* TRANSLATORS: This refers to a sequence of escape codes
1256 		 * (from the keyboard) that nano does not recognize. */
1257 		statusline(AHEM, _("Unknown sequence"));
1258 	else if (code > 0x7F)
1259 		statusline(AHEM, _("Unbound key"));
1260 	else if (meta_key) {
1261 #ifndef NANO_TINY
1262 		if (code < 0x20)
1263 			statusline(AHEM, _("Unbindable key: M-^%c"), code + 0x40);
1264 		else
1265 #endif
1266 #ifdef ENABLE_NANORC
1267 		if (shifted_metas && 'A' <= code && code <= 'Z')
1268 			statusline(AHEM, _("Unbound key: Sh-M-%c"), code);
1269 		else
1270 #endif
1271 			statusline(AHEM, _("Unbound key: M-%c"), toupper(code));
1272 	} else if (code == ESC_CODE)
1273 		statusline(AHEM, _("Unbindable key: ^["));
1274 	else if (code < 0x20)
1275 		statusline(AHEM, _("Unbound key: ^%c"), code + 0x40);
1276 #if defined(ENABLE_BROWSER) || defined (ENABLE_HELP)
1277 	else
1278 		statusline(AHEM, _("Unbound key: %c"), code);
1279 #endif
1280 	set_blankdelay_to_one();
1281 }
1282 
1283 #ifdef ENABLE_MOUSE
1284 /* Handle a mouse click on the edit window or the shortcut list. */
do_mouse(void)1285 int do_mouse(void)
1286 {
1287 	int click_row, click_col;
1288 	int retval = get_mouseinput(&click_row, &click_col, TRUE);
1289 
1290 	/* If the click is wrong or already handled, we're done. */
1291 	if (retval != 0)
1292 		return retval;
1293 
1294 	/* If the click was in the edit window, put the cursor in that spot. */
1295 	if (wmouse_trafo(edit, &click_row, &click_col, FALSE)) {
1296 		linestruct *current_save = openfile->current;
1297 		ssize_t row_count = click_row - openfile->current_y;
1298 		size_t leftedge;
1299 #ifndef NANO_TINY
1300 		size_t current_x_save = openfile->current_x;
1301 		bool sameline = (click_row == openfile->current_y);
1302 			/* Whether the click was on the row where the cursor is. */
1303 
1304 		if (ISSET(SOFTWRAP))
1305 			leftedge = leftedge_for(xplustabs(), openfile->current);
1306 		else
1307 #endif
1308 			leftedge = get_page_start(xplustabs());
1309 
1310 		/* Move current up or down to the row that was clicked on. */
1311 		if (row_count < 0)
1312 			go_back_chunks(-row_count, &openfile->current, &leftedge);
1313 		else
1314 			go_forward_chunks(row_count, &openfile->current, &leftedge);
1315 
1316 		openfile->current_x = actual_x(openfile->current->data,
1317 								actual_last_column(leftedge, click_col));
1318 
1319 #ifndef NANO_TINY
1320 		/* Clicking where the cursor is toggles the mark, as does clicking
1321 		 * beyond the line length with the cursor at the end of the line. */
1322 		if (sameline && openfile->current_x == current_x_save) {
1323 			do_mark();
1324 			if (ISSET(STATEFLAGS))
1325 				titlebar(NULL);
1326 		} else
1327 #endif
1328 			/* The cursor moved; clean the cutbuffer on the next cut. */
1329 			keep_cutbuffer = FALSE;
1330 
1331 		edit_redraw(current_save, CENTERING);
1332 	}
1333 
1334 	/* No more handling is needed. */
1335 	return 2;
1336 }
1337 #endif /* ENABLE_MOUSE */
1338 
1339 /* Return TRUE when the given function is a cursor-moving command. */
wanted_to_move(void (* func)(void))1340 bool wanted_to_move(void (*func)(void))
1341 {
1342 	return func == do_left || func == do_right ||
1343 			func == do_up || func == do_down ||
1344 			func == do_home || func == do_end ||
1345 			func == to_prev_word || func == to_next_word ||
1346 #ifdef ENABLE_JUSTIFY
1347 			func == to_para_begin || func == to_para_end ||
1348 #endif
1349 			func == to_prev_block || func == to_next_block ||
1350 			func == do_page_up || func == do_page_down ||
1351 			func == to_first_line || func == to_last_line;
1352 }
1353 
1354 /* Return TRUE when the given shortcut is admissible in view mode. */
okay_for_view(const keystruct * shortcut)1355 bool okay_for_view(const keystruct *shortcut)
1356 {
1357 	funcstruct *item = allfuncs;
1358 
1359 	/* Search the function of the given shortcut in the list of functions. */
1360 	while (item != NULL && item->func != shortcut->func)
1361 		item = item->next;
1362 
1363 	return (item == NULL || item->viewok);
1364 }
1365 
1366 #ifndef NANO_TINY
1367 /* Read in all waiting input bytes and paste them into the buffer in one go. */
suck_up_input_and_paste_it(void)1368 void suck_up_input_and_paste_it(void)
1369 {
1370 	linestruct *was_cutbuffer = cutbuffer;
1371 	linestruct *line = make_new_node(NULL);
1372 	size_t index = 0;
1373 
1374 	line->data = copy_of("");
1375 	cutbuffer = line;
1376 
1377 	while (bracketed_paste) {
1378 		int input = get_kbinput(edit, BLIND);
1379 
1380 		if (input == '\r' || input == '\n') {
1381 			line->next = make_new_node(line);
1382 			line = line->next;
1383 			line->data = copy_of("");
1384 			index = 0;
1385 		} else if ((0x20 <= input && input <= 0xFF && input != DEL_CODE) ||
1386 														input == '\t') {
1387 			line->data = nrealloc(line->data, index + 2);
1388 			line->data[index++] = (char)input;
1389 			line->data[index] = '\0';
1390 		} else if (input != BRACKETED_PASTE_MARKER)
1391 			beep();
1392 	}
1393 
1394 	paste_text();
1395 
1396 	free_lines(cutbuffer);
1397 	cutbuffer = was_cutbuffer;
1398 }
1399 #endif
1400 
1401 /* Insert the given short burst of bytes into the edit buffer. */
inject(char * burst,size_t count)1402 void inject(char *burst, size_t count)
1403 {
1404 	linestruct *thisline = openfile->current;
1405 	size_t datalen = strlen(thisline->data);
1406 #ifndef NANO_TINY
1407 	size_t original_row = 0;
1408 	size_t old_amount = 0;
1409 
1410 	if (ISSET(SOFTWRAP)) {
1411 		if (openfile->current_y == editwinrows - 1)
1412 			original_row = chunk_for(xplustabs(), thisline);
1413 		old_amount = extra_chunks_in(thisline);
1414 	}
1415 #endif
1416 
1417 	/* Encode an embedded NUL byte as 0x0A. */
1418 	for (size_t index = 0; index < count; index++)
1419 		if (burst[index] == '\0')
1420 			burst[index] = '\n';
1421 
1422 #ifndef NANO_TINY
1423 	/* Only add a new undo item when the current item is not an ADD or when
1424 	 * the current typing is not contiguous with the previous typing. */
1425 	if (openfile->last_action != ADD ||
1426 				openfile->current_undo->tail_lineno != thisline->lineno ||
1427 				openfile->current_undo->tail_x != openfile->current_x)
1428 		add_undo(ADD, NULL);
1429 #endif
1430 
1431 	/* Make room for the new bytes and copy them into the line. */
1432 	thisline->data = nrealloc(thisline->data, datalen + count + 1);
1433 	memmove(thisline->data + openfile->current_x + count,
1434 						thisline->data + openfile->current_x,
1435 						datalen - openfile->current_x + 1);
1436 	strncpy(thisline->data + openfile->current_x, burst, count);
1437 
1438 #ifndef NANO_TINY
1439 	/* When the mark is to the right of the cursor, compensate its position. */
1440 	if (thisline == openfile->mark && openfile->current_x < openfile->mark_x)
1441 		openfile->mark_x += count;
1442 
1443 	/* When the cursor is on the top row and not on the first chunk
1444 	 * of a line, adding text there might change the preceding chunk
1445 	 * and thus require an adjustment of firstcolumn. */
1446 	if (thisline == openfile->edittop && openfile->firstcolumn > 0) {
1447 		ensure_firstcolumn_is_aligned();
1448 		refresh_needed = TRUE;
1449 	}
1450 #endif
1451 	/* If text was added to the magic line, create a new magic line. */
1452 	if (thisline == openfile->filebot && !ISSET(NO_NEWLINES)) {
1453 		new_magicline();
1454 		if (margin > 0)
1455 			refresh_needed = TRUE;
1456 	}
1457 
1458 	openfile->current_x += count;
1459 
1460 	openfile->totsize += mbstrlen(burst);
1461 	set_modified();
1462 
1463 #ifndef NANO_TINY
1464 	update_undo(ADD);
1465 #endif
1466 
1467 #ifdef ENABLE_WRAPPING
1468 	/* Wrap the line when needed, and if so, schedule a refresh. */
1469 	if (ISSET(BREAK_LONG_LINES) && do_wrap())
1470 		refresh_needed = TRUE;
1471 #endif
1472 
1473 #ifndef NANO_TINY
1474 	/* When softwrapping and the number of chunks in the current line changed,
1475 	 * or we were on the last row of the edit window and moved to a new chunk,
1476 	 * we need a full refresh. */
1477 	if (ISSET(SOFTWRAP) && (extra_chunks_in(openfile->current) != old_amount ||
1478 					(openfile->current_y == editwinrows - 1 &&
1479 					chunk_for(xplustabs(), openfile->current) > original_row))) {
1480 		refresh_needed = TRUE;
1481 		focusing = FALSE;
1482 	}
1483 #endif
1484 
1485 	openfile->placewewant = xplustabs();
1486 
1487 #ifdef ENABLE_COLOR
1488 	if (!refresh_needed)
1489 		check_the_multis(openfile->current);
1490 #endif
1491 	if (!refresh_needed)
1492 		update_line(openfile->current, openfile->current_x);
1493 }
1494 
1495 /* Read in a keystroke, and execute its command or insert it into the buffer. */
process_a_keystroke(void)1496 void process_a_keystroke(void)
1497 {
1498 	int input;
1499 		/* The keystroke we read in: a character or a shortcut. */
1500 	static char *puddle = NULL;
1501 		/* The input buffer for actual characters. */
1502 	static size_t depth = 0;
1503 		/* The length of the input buffer. */
1504 #ifndef NANO_TINY
1505 	linestruct *was_mark = openfile->mark;
1506 #endif
1507 	static bool give_a_hint = TRUE;
1508 	const keystruct *shortcut;
1509 
1510 	/* Read in a keystroke, and show the cursor while waiting. */
1511 	input = get_kbinput(edit, VISIBLE);
1512 
1513 	lastmessage = VACUUM;
1514 	hide_cursor = FALSE;
1515 
1516 #ifndef NANO_TINY
1517 	if (input == KEY_WINCH)
1518 		return;
1519 #endif
1520 #ifdef ENABLE_MOUSE
1521 	if (input == KEY_MOUSE) {
1522 		/* If the user clicked on a shortcut, read in the key code that it was
1523 		 * converted into.  Else the click has been handled or was invalid. */
1524 		if (do_mouse() == 1)
1525 			input = get_kbinput(edit, BLIND);
1526 		else
1527 			return;
1528 	}
1529 #endif
1530 
1531 	/* Check for a shortcut in the main list. */
1532 	shortcut = get_shortcut(&input);
1533 
1534 	/* If not a command, discard anything that is not a normal character byte. */
1535 	if (shortcut == NULL) {
1536 		if (input < 0x20 || input > 0xFF || meta_key)
1537 			unbound_key(input);
1538 		else if (ISSET(VIEW_MODE))
1539 			print_view_warning();
1540 		else {
1541 #ifndef NANO_TINY
1542 			if (openfile->mark && openfile->softmark) {
1543 				openfile->mark = NULL;
1544 				refresh_needed = TRUE;
1545 			}
1546 #endif
1547 			/* Store the byte, and leave room for a terminating zero. */
1548 			puddle = nrealloc(puddle, depth + 2);
1549 			puddle[depth++] = (char)input;
1550 		}
1551 	}
1552 
1553 	/* If we have a command, or if there aren't any other key codes waiting,
1554 	 * it's time to insert the gathered bytes into the edit buffer. */
1555 	if ((shortcut || get_key_buffer_len() == 0) && puddle != NULL) {
1556 		puddle[depth] = '\0';
1557 
1558 		inject(puddle, depth);
1559 
1560 		free(puddle);
1561 		puddle = NULL;
1562 		depth = 0;
1563 	}
1564 
1565 	if (shortcut == NULL) {
1566 		pletion_line = NULL;
1567 		keep_cutbuffer = FALSE;
1568 		return;
1569 	}
1570 
1571 	if (ISSET(VIEW_MODE) && !okay_for_view(shortcut)) {
1572 		print_view_warning();
1573 		return;
1574 	}
1575 
1576 	if (input == '\b' && give_a_hint && openfile->current_x == 0 &&
1577 				openfile->current == openfile->filetop && !ISSET(NO_HELP)) {
1578 		statusbar(_("^W = Ctrl+W    M-W = Alt+W"));
1579 		give_a_hint = FALSE;
1580 	} else if (meta_key)
1581 		give_a_hint = FALSE;
1582 
1583 	/* When not cutting or copying text, drop the cutbuffer the next time. */
1584 	if (shortcut->func != cut_text) {
1585 #ifndef NANO_TINY
1586 		if (shortcut->func != copy_text && shortcut->func != zap_text)
1587 #endif
1588 			keep_cutbuffer = FALSE;
1589 	}
1590 
1591 #ifdef ENABLE_WORDCOMPLETION
1592 	if (shortcut->func != complete_a_word)
1593 		pletion_line = NULL;
1594 #endif
1595 #ifdef ENABLE_NANORC
1596 	if (shortcut->func == (functionptrtype)implant) {
1597 		implant(shortcut->expansion);
1598 		return;
1599 	}
1600 #endif
1601 #ifndef NANO_TINY
1602 	if (shortcut->func == do_toggle_void) {
1603 		do_toggle(shortcut->toggle);
1604 		if (shortcut->toggle == CUT_FROM_CURSOR)
1605 			keep_cutbuffer = FALSE;
1606 		return;
1607 	}
1608 
1609 	linestruct *was_current = openfile->current;
1610 	size_t was_x = openfile->current_x;
1611 
1612 	/* If Shifted movement occurs, set the mark. */
1613 	if (shift_held && !openfile->mark) {
1614 		openfile->mark = openfile->current;
1615 		openfile->mark_x = openfile->current_x;
1616 		openfile->softmark = TRUE;
1617 	}
1618 #endif
1619 
1620 	/* Execute the function of the shortcut. */
1621 	shortcut->func();
1622 
1623 #ifndef NANO_TINY
1624 	/* When the marked region changes without Shift being held,
1625 	 * discard a soft mark.  And when the marked region covers a
1626 	 * different set of lines, reset  the "last line too" flag. */
1627 	if (openfile->mark) {
1628 		if (!shift_held && openfile->softmark &&
1629 							(openfile->current != was_current ||
1630 							openfile->current_x != was_x ||
1631 							wanted_to_move(shortcut->func))) {
1632 			openfile->mark = NULL;
1633 			refresh_needed = TRUE;
1634 		} else if (openfile->current != was_current)
1635 			also_the_last = FALSE;
1636 	}
1637 #endif
1638 #ifdef ENABLE_COLOR
1639 	if (!refresh_needed && !okay_for_view(shortcut))
1640 		check_the_multis(openfile->current);
1641 #endif
1642 	if (!refresh_needed && (shortcut->func == do_delete ||
1643 							shortcut->func == do_backspace))
1644 		update_line(openfile->current, openfile->current_x);
1645 
1646 #ifndef NANO_TINY
1647 	if (bracketed_paste)
1648 		suck_up_input_and_paste_it();
1649 
1650 	if (ISSET(STATEFLAGS) && openfile->mark != was_mark)
1651 		titlebar(NULL);
1652 #endif
1653 }
1654 
main(int argc,char ** argv)1655 int main(int argc, char **argv)
1656 {
1657 	int stdin_flags, optchr;
1658 #ifdef ENABLE_NANORC
1659 	bool ignore_rcfiles = FALSE;
1660 		/* Whether to ignore the nanorc files. */
1661 #endif
1662 #if defined(ENABLED_WRAPORJUSTIFY) && defined(ENABLE_NANORC)
1663 	bool fill_used = FALSE;
1664 		/* Was the fill option used on the command line? */
1665 #endif
1666 #ifdef ENABLE_WRAPPING
1667 	int hardwrap = -2;
1668 		/* Becomes 0 when --nowrap and 1 when --breaklonglines is used. */
1669 #endif
1670 #ifdef ENABLE_JUSTIFY
1671 	int quoterc;
1672 		/* Whether the quoting regex was compiled successfully. */
1673 #endif
1674 	const struct option long_options[] = {
1675 		{"boldtext", 0, NULL, 'D'},
1676 #ifdef ENABLE_MULTIBUFFER
1677 		{"multibuffer", 0, NULL, 'F'},
1678 #endif
1679 #ifdef ENABLE_NANORC
1680 		{"ignorercfiles", 0, NULL, 'I'},
1681 #endif
1682 		{"rawsequences", 0, NULL, 'K'},
1683 #ifdef ENABLED_WRAPORJUSTIFY
1684 		{"trimblanks", 0, NULL, 'M'},
1685 #endif
1686 #ifdef ENABLE_JUSTIFY
1687 		{"quotestr", 1, NULL, 'Q'},
1688 #endif
1689 		{"restricted", 0, NULL, 'R'},
1690 		{"quickblank", 0, NULL, 'U'},
1691 		{"version", 0, NULL, 'V'},
1692 #ifdef ENABLE_COLOR
1693 		{"syntax", 1, NULL, 'Y'},
1694 #endif
1695 #ifdef ENABLE_WRAPPING
1696 		{"breaklonglines", 0, NULL, 'b'},
1697 #endif
1698 		{"constantshow", 0, NULL, 'c'},
1699 		{"rebinddelete", 0, NULL, 'd'},
1700 #ifdef ENABLE_NANORC
1701 		{"rcfile", 1, NULL, 'f'},
1702 #endif
1703 #if defined(ENABLE_BROWSER) || defined(ENABLE_HELP)
1704 		{"showcursor", 0, NULL, 'g'},
1705 #endif
1706 		{"help", 0, NULL, 'h'},
1707 #ifdef ENABLE_LINENUMBERS
1708 		{"linenumbers", 0, NULL, 'l'},
1709 #endif
1710 #ifdef ENABLE_MOUSE
1711 		{"mouse", 0, NULL, 'm'},
1712 #endif
1713 #ifdef ENABLE_OPERATINGDIR
1714 		{"operatingdir", 1, NULL, 'o'},
1715 #endif
1716 		{"preserve", 0, NULL, 'p'},
1717 #ifdef ENABLED_WRAPORJUSTIFY
1718 		{"fill", 1, NULL, 'r'},
1719 #endif
1720 #ifdef ENABLE_SPELLER
1721 		{"speller", 1, NULL, 's'},
1722 #endif
1723 		{"saveonexit", 0, NULL, 't'},
1724 		{"tempfile", 0, NULL, 't'},  /* Deprecated; remove in 2022. */
1725 		{"view", 0, NULL, 'v'},
1726 #ifdef ENABLE_WRAPPING
1727 		{"nowrap", 0, NULL, 'w'},
1728 #endif
1729 		{"nohelp", 0, NULL, 'x'},
1730 		{"suspendable", 0, NULL, 'z'},
1731 #ifndef NANO_TINY
1732 		{"smarthome", 0, NULL, 'A'},
1733 		{"backup", 0, NULL, 'B'},
1734 		{"backupdir", 1, NULL, 'C'},
1735 		{"tabstospaces", 0, NULL, 'E'},
1736 		{"locking", 0, NULL, 'G'},
1737 		{"historylog", 0, NULL, 'H'},
1738 		{"guidestripe", 1, NULL, 'J'},
1739 		{"nonewlines", 0, NULL, 'L'},
1740 		{"noconvert", 0, NULL, 'N'},
1741 		{"bookstyle", 0, NULL, 'O'},
1742 		{"positionlog", 0, NULL, 'P'},
1743 		{"softwrap", 0, NULL, 'S'},
1744 		{"tabsize", 1, NULL, 'T'},
1745 		{"wordbounds", 0, NULL, 'W'},
1746 		{"wordchars", 1, NULL, 'X'},
1747 		{"zap", 0, NULL, 'Z'},
1748 		{"atblanks", 0, NULL, 'a'},
1749 		{"emptyline", 0, NULL, 'e'},
1750 		{"autoindent", 0, NULL, 'i'},
1751 		{"jumpyscrolling", 0, NULL, 'j'},
1752 		{"cutfromcursor", 0, NULL, 'k'},
1753 		{"noread", 0, NULL, 'n'},
1754 		{"indicator", 0, NULL, 'q'},
1755 		{"unix", 0, NULL, 'u'},
1756 		{"afterends", 0, NULL, 'y'},
1757 		{"stateflags", 0, NULL, '%'},
1758 		{"minibar", 0, NULL, '_'},
1759 #endif
1760 #ifdef HAVE_LIBMAGIC
1761 		{"magic", 0, NULL, '!'},
1762 #endif
1763 		{NULL, 0, NULL, 0}
1764 	};
1765 
1766 #ifdef __linux__
1767 	struct vt_stat dummy;
1768 
1769 	/* Check whether we're running on a Linux console. */
1770 	on_a_vt = (ioctl(STDOUT_FILENO, VT_GETSTATE, &dummy) == 0);
1771 #endif
1772 
1773 	/* Back up the terminal settings so that they can be restored. */
1774 	tcgetattr(STDIN_FILENO, &original_state);
1775 
1776 	/* Get the state of standard input and ensure it uses blocking mode. */
1777 	stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
1778 	if (stdin_flags != -1)
1779 		fcntl(STDIN_FILENO, F_SETFL, stdin_flags & ~O_NONBLOCK);
1780 
1781 #ifdef ENABLE_UTF8
1782 	/* If setting the locale is successful and it uses UTF-8, we will
1783 	 * need to use the multibyte functions for text processing. */
1784 	if (setlocale(LC_ALL, "") && strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
1785 		utf8_init();
1786 #else
1787 	setlocale(LC_ALL, "");
1788 #endif
1789 
1790 #ifdef ENABLE_NLS
1791 	bindtextdomain(PACKAGE, LOCALEDIR);
1792 	textdomain(PACKAGE);
1793 #endif
1794 
1795 	/* Set a sensible default, different from what Pico does. */
1796 	SET(NO_WRAP);
1797 
1798 	/* If the executable's name starts with 'r', activate restricted mode. */
1799 	if (*(tail(argv[0])) == 'r')
1800 		SET(RESTRICTED);
1801 
1802 	while ((optchr = getopt_long(argc, argv, "ABC:DEFGHIJ:KLMNOPQ:RST:UVWX:Y:Z"
1803 				"abcdef:ghijklmno:pqr:s:tuvwxyz$%_!", long_options, NULL)) != -1) {
1804 		switch (optchr) {
1805 #ifndef NANO_TINY
1806 			case 'A':
1807 				SET(SMART_HOME);
1808 				break;
1809 			case 'B':
1810 				SET(MAKE_BACKUP);
1811 				break;
1812 			case 'C':
1813 				backup_dir = mallocstrcpy(backup_dir, optarg);
1814 				break;
1815 #endif
1816 			case 'D':
1817 				SET(BOLD_TEXT);
1818 				break;
1819 #ifndef NANO_TINY
1820 			case 'E':
1821 				SET(TABS_TO_SPACES);
1822 				break;
1823 #endif
1824 #ifdef ENABLE_MULTIBUFFER
1825 			case 'F':
1826 				SET(MULTIBUFFER);
1827 				break;
1828 #endif
1829 #ifndef NANO_TINY
1830 			case 'G':
1831 				SET(LOCKING);
1832 				break;
1833 #endif
1834 #ifdef ENABLE_HISTORIES
1835 			case 'H':
1836 				SET(HISTORYLOG);
1837 				break;
1838 #endif
1839 #ifdef ENABLE_NANORC
1840 			case 'I':
1841 				ignore_rcfiles = TRUE;
1842 				break;
1843 #endif
1844 #ifndef NANO_TINY
1845 			case 'J':
1846 				if (!parse_num(optarg, &stripe_column) || stripe_column <= 0) {
1847 					fprintf(stderr, _("Guide column \"%s\" is invalid"), optarg);
1848 					fprintf(stderr, "\n");
1849 					exit(1);
1850 				}
1851 				break;
1852 #endif
1853 			case 'K':
1854 				SET(RAW_SEQUENCES);
1855 				break;
1856 #ifndef NANO_TINY
1857 			case 'L':
1858 				SET(NO_NEWLINES);
1859 				break;
1860 #endif
1861 #ifdef ENABLED_WRAPORJUSTIFY
1862 			case 'M':
1863 				SET(TRIM_BLANKS);
1864 				break;
1865 #endif
1866 #ifndef NANO_TINY
1867 			case 'N':
1868 				SET(NO_CONVERT);
1869 				break;
1870 			case 'O':
1871 				SET(BOOKSTYLE);
1872 				break;
1873 #endif
1874 #ifdef ENABLE_HISTORIES
1875 			case 'P':
1876 				SET(POSITIONLOG);
1877 				break;
1878 #endif
1879 #ifdef ENABLE_JUSTIFY
1880 			case 'Q':
1881 				quotestr = mallocstrcpy(quotestr, optarg);
1882 				break;
1883 #endif
1884 			case 'R':
1885 				SET(RESTRICTED);
1886 				break;
1887 #ifndef NANO_TINY
1888 			case 'S':
1889 			case '$':  /* Deprecated; remove in 2024. */
1890 				SET(SOFTWRAP);
1891 				break;
1892 			case 'T':
1893 				if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
1894 					fprintf(stderr, _("Requested tab size \"%s\" is invalid"), optarg);
1895 					fprintf(stderr, "\n");
1896 					exit(1);
1897 				}
1898 				break;
1899 #endif
1900 			case 'U':
1901 				SET(QUICK_BLANK);
1902 				break;
1903 			case 'V':
1904 				version();
1905 				exit(0);
1906 #ifndef NANO_TINY
1907 			case 'W':
1908 				SET(WORD_BOUNDS);
1909 				break;
1910 			case 'X':
1911 				word_chars = mallocstrcpy(word_chars, optarg);
1912 				break;
1913 #endif
1914 #ifdef ENABLE_COLOR
1915 			case 'Y':
1916 				syntaxstr = mallocstrcpy(syntaxstr, optarg);
1917 				break;
1918 #endif
1919 #ifndef NANO_TINY
1920 			case 'Z':
1921 				SET(LET_THEM_ZAP);
1922 				break;
1923 			case 'a':
1924 				SET(AT_BLANKS);
1925 				break;
1926 #endif
1927 #ifdef ENABLE_WRAPPING
1928 			case 'b':
1929 				hardwrap = 1;
1930 				break;
1931 #endif
1932 			case 'c':
1933 				SET(CONSTANT_SHOW);
1934 				break;
1935 			case 'd':
1936 				SET(REBIND_DELETE);
1937 				break;
1938 #ifndef NANO_TINY
1939 			case 'e':
1940 				SET(EMPTY_LINE);
1941 				break;
1942 #endif
1943 #ifdef ENABLE_NANORC
1944 			case 'f':
1945 				custom_nanorc = mallocstrcpy(custom_nanorc, optarg);
1946 				break;
1947 #endif
1948 #if defined(ENABLE_BROWSER) || defined(ENABLE_HELP)
1949 			case 'g':
1950 				SET(SHOW_CURSOR);
1951 				break;
1952 #endif
1953 			case 'h':
1954 				usage();
1955 				exit(0);
1956 #ifndef NANO_TINY
1957 			case 'i':
1958 				SET(AUTOINDENT);
1959 				break;
1960 			case 'j':
1961 				SET(JUMPY_SCROLLING);
1962 				break;
1963 			case 'k':
1964 				SET(CUT_FROM_CURSOR);
1965 				break;
1966 #endif
1967 #ifdef ENABLE_LINENUMBERS
1968 			case 'l':
1969 				SET(LINE_NUMBERS);
1970 				break;
1971 #endif
1972 #ifdef ENABLE_MOUSE
1973 			case 'm':
1974 				SET(USE_MOUSE);
1975 				break;
1976 #endif
1977 #ifndef NANO_TINY
1978 			case 'n':
1979 				SET(NOREAD_MODE);
1980 				break;
1981 #endif
1982 #ifdef ENABLE_OPERATINGDIR
1983 			case 'o':
1984 				operating_dir = mallocstrcpy(operating_dir, optarg);
1985 				break;
1986 #endif
1987 			case 'p':
1988 				SET(PRESERVE);
1989 				break;
1990 #ifndef NANO_TINY
1991 			case 'q':
1992 				SET(INDICATOR);
1993 				break;
1994 #endif
1995 #ifdef ENABLED_WRAPORJUSTIFY
1996 			case 'r':
1997 				if (!parse_num(optarg, &fill)) {
1998 					fprintf(stderr, _("Requested fill size \"%s\" is invalid"), optarg);
1999 					fprintf(stderr, "\n");
2000 					exit(1);
2001 				}
2002 #ifdef ENABLE_NANORC
2003 				fill_used = TRUE;
2004 #endif
2005 				break;
2006 #endif
2007 #ifdef ENABLE_SPELLER
2008 			case 's':
2009 				alt_speller = mallocstrcpy(alt_speller, optarg);
2010 				break;
2011 #endif
2012 			case 't':
2013 				SET(SAVE_ON_EXIT);
2014 				break;
2015 #ifndef NANO_TINY
2016 			case 'u':
2017 				SET(MAKE_IT_UNIX);
2018 				break;
2019 #endif
2020 			case 'v':
2021 				SET(VIEW_MODE);
2022 				break;
2023 #ifdef ENABLE_WRAPPING
2024 			case 'w':
2025 				hardwrap = 0;
2026 				break;
2027 #endif
2028 			case 'x':
2029 				SET(NO_HELP);
2030 				break;
2031 #ifndef NANO_TINY
2032 			case 'y':
2033 				SET(AFTER_ENDS);
2034 				break;
2035 #endif
2036 			case 'z':
2037 				SET(SUSPENDABLE);
2038 				break;
2039 #ifndef NANO_TINY
2040 			case '%':
2041 				SET(STATEFLAGS);
2042 				break;
2043 			case '_':
2044 				SET(MINIBAR);
2045 				break;
2046 #endif
2047 #ifdef HAVE_LIBMAGIC
2048 			case '!':
2049 				SET(USE_MAGIC);
2050 				break;
2051 #endif
2052 			default:
2053 				printf(_("Type '%s -h' for a list of available options.\n"), argv[0]);
2054 				exit(1);
2055 		}
2056 	}
2057 
2058 	/* Curses needs TERM; if it is unset, try falling back to a VT220. */
2059 	if (getenv("TERM") == NULL)
2060 		setenv("TERM", "vt220", 0);
2061 
2062 	/* Enter into curses mode.  Abort if this fails. */
2063 	if (initscr() == NULL)
2064 		exit(1);
2065 
2066 #ifdef ENABLE_COLOR
2067 	/* If the terminal can do colors, tell ncurses to switch them on. */
2068 	if (has_colors())
2069 		start_color();
2070 #endif
2071 
2072 	/* Set up the function and shortcut lists.  This needs to be done
2073 	 * before reading the rcfile, to be able to rebind/unbind keys. */
2074 	shortcut_init();
2075 
2076 #ifdef ENABLE_NANORC
2077 	if (!ignore_rcfiles) {
2078 		/* Back up the command-line options that take an argument. */
2079 #ifdef ENABLED_WRAPORJUSTIFY
2080 		ssize_t fill_cmdline = fill;
2081 #endif
2082 #ifndef NANO_TINY
2083 		char *backup_dir_cmdline = backup_dir;
2084 		char *word_chars_cmdline = word_chars;
2085 		size_t stripeclm_cmdline = stripe_column;
2086 		ssize_t tabsize_cmdline = tabsize;
2087 #endif
2088 #ifdef ENABLE_OPERATINGDIR
2089 		char *operating_dir_cmdline = operating_dir;
2090 #endif
2091 #ifdef ENABLE_JUSTIFY
2092 		char *quotestr_cmdline = quotestr;
2093 #endif
2094 #ifdef ENABLE_SPELLER
2095 		char *alt_speller_cmdline = alt_speller;
2096 #endif
2097 
2098 		/* Back up the command-line flags. */
2099 		unsigned flags_cmdline[sizeof(flags) / sizeof(flags[0])];
2100 		memcpy(flags_cmdline, flags, sizeof(flags_cmdline));
2101 
2102 		/* Clear the string options, to not overwrite the specified ones. */
2103 #ifndef NANO_TINY
2104 		backup_dir = NULL;
2105 		word_chars = NULL;
2106 #endif
2107 #ifdef ENABLE_OPERATINGDIR
2108 		operating_dir = NULL;
2109 #endif
2110 #ifdef ENABLE_JUSTIFY
2111 		quotestr = NULL;
2112 #endif
2113 #ifdef ENABLE_SPELLER
2114 		alt_speller = NULL;
2115 #endif
2116 		/* Now process the system's and the user's nanorc file, if any. */
2117 		do_rcfiles();
2118 
2119 		/* If the backed-up command-line options have a value, restore them. */
2120 #ifdef ENABLED_WRAPORJUSTIFY
2121 		if (fill_used)
2122 			fill = fill_cmdline;
2123 #endif
2124 #ifndef NANO_TINY
2125 		if (backup_dir_cmdline != NULL) {
2126 			free(backup_dir);
2127 			backup_dir = backup_dir_cmdline;
2128 		}
2129 		if (word_chars_cmdline != NULL) {
2130 			free(word_chars);
2131 			word_chars = word_chars_cmdline;
2132 		}
2133 		if (stripeclm_cmdline > 0)
2134 			stripe_column = stripeclm_cmdline;
2135 		if (tabsize_cmdline != -1)
2136 			tabsize = tabsize_cmdline;
2137 #endif
2138 #ifdef ENABLE_OPERATINGDIR
2139 		if (operating_dir_cmdline != NULL || ISSET(RESTRICTED)) {
2140 			free(operating_dir);
2141 			operating_dir = operating_dir_cmdline;
2142 		}
2143 #endif
2144 #ifdef ENABLE_JUSTIFY
2145 		if (quotestr_cmdline != NULL) {
2146 			free(quotestr);
2147 			quotestr = quotestr_cmdline;
2148 		}
2149 #endif
2150 #ifdef ENABLE_SPELLER
2151 		if (alt_speller_cmdline != NULL) {
2152 			free(alt_speller);
2153 			alt_speller = alt_speller_cmdline;
2154 		}
2155 		/* Strip leading whitespace from the speller command, if any. */
2156 		while (alt_speller && *alt_speller && isblank(*alt_speller))
2157 			memmove(alt_speller, alt_speller + 1, strlen(alt_speller));
2158 #endif
2159 
2160 		/* If an rcfile undid the default setting, copy it to the new flag. */
2161 		if (!ISSET(NO_WRAP))
2162 			SET(BREAK_LONG_LINES);
2163 
2164 		/* Simply OR the boolean flags from rcfile and command line. */
2165 		for (size_t i = 0; i < sizeof(flags) / sizeof(flags[0]); i++)
2166 			flags[i] |= flags_cmdline[i];
2167 	}
2168 #endif /* ENABLE_NANORC */
2169 
2170 #ifdef ENABLE_WRAPPING
2171 	if (hardwrap == 0)
2172 		UNSET(BREAK_LONG_LINES);
2173 	else if (hardwrap == 1)
2174 		SET(BREAK_LONG_LINES);
2175 #endif
2176 
2177 	/* If the user wants bold instead of reverse video for hilited text... */
2178 	if (ISSET(BOLD_TEXT))
2179 		hilite_attribute = A_BOLD;
2180 
2181 	/* When in restricted mode, disable backups, suspending, and history files,
2182 	 * since they allow writing to files not specified on the command line. */
2183 	if (ISSET(RESTRICTED)) {
2184 		UNSET(MAKE_BACKUP);
2185 		UNSET(SUSPENDABLE);
2186 #ifdef ENABLE_NANORC
2187 		UNSET(HISTORYLOG);
2188 		UNSET(POSITIONLOG);
2189 #endif
2190 	}
2191 
2192 	/* When getting untranslated escape sequences, the mouse cannot be used. */
2193 	if (ISSET(RAW_SEQUENCES))
2194 		UNSET(USE_MOUSE);
2195 
2196 #ifdef ENABLE_HISTORIES
2197 	/* Initialize the pointers for the Search/Replace/Execute histories. */
2198 	history_init();
2199 
2200 	/* If we need history files, verify that we have a directory for them,
2201 	 * and when not, cancel the options. */
2202 	if ((ISSET(HISTORYLOG) || ISSET(POSITIONLOG)) && !have_statedir()) {
2203 		UNSET(HISTORYLOG);
2204 		UNSET(POSITIONLOG);
2205 	}
2206 
2207 	/* If the user wants history persistence, read the relevant files. */
2208 	if (ISSET(HISTORYLOG))
2209 		load_history();
2210 	if (ISSET(POSITIONLOG))
2211 		load_poshistory();
2212 #endif
2213 
2214 #ifndef NANO_TINY
2215 	/* If a backup directory was specified and we're not in restricted mode,
2216 	 * verify it is an existing folder, so backup files can be saved there. */
2217 	if (backup_dir != NULL && !ISSET(RESTRICTED))
2218 		init_backup_dir();
2219 #endif
2220 #ifdef ENABLE_OPERATINGDIR
2221 	/* Set up the operating directory.  This entails chdir()ing there,
2222 	 * so that file reads and writes will be based there. */
2223 	if (operating_dir != NULL)
2224 		init_operating_dir();
2225 #endif
2226 
2227 #ifdef ENABLE_JUSTIFY
2228 	/* Set the default value for things that weren't specified. */
2229 	if (punct == NULL)
2230 		punct = copy_of("!.?");
2231 	if (brackets == NULL)
2232 		brackets = copy_of("\"')>]}");
2233 	if (quotestr == NULL)
2234 		quotestr = copy_of("^([ \t]*([!#%:;>|}]|/{2}))+");
2235 
2236 	/* Compile the quoting regex, and exit when it's invalid. */
2237 	quoterc = regcomp(&quotereg, quotestr, NANO_REG_EXTENDED);
2238 	if (quoterc != 0) {
2239 		size_t size = regerror(quoterc, &quotereg, NULL, 0);
2240 		char *message = nmalloc(size);
2241 
2242 		regerror(quoterc, &quotereg, message, size);
2243 		die(_("Bad quoting regex \"%s\": %s\n"), quotestr, message);
2244 	} else
2245 		free(quotestr);
2246 #endif
2247 
2248 #ifdef ENABLE_SPELLER
2249 	/* If we don't have an alternative spell checker after reading the
2250 	 * command line and/or rcfile(s), check $SPELL for one, as Pico
2251 	 * does (unless we're using restricted mode, in which case spell
2252 	 * checking is disabled, since it would allow reading from or
2253 	 * writing to files not specified on the command line). */
2254 	if (alt_speller == NULL && !ISSET(RESTRICTED)) {
2255 		const char *spellenv = getenv("SPELL");
2256 
2257 		if (spellenv != NULL)
2258 			alt_speller = copy_of(spellenv);
2259 	}
2260 #endif
2261 
2262 #ifndef NANO_TINY
2263 	/* If matchbrackets wasn't specified, set its default value. */
2264 	if (matchbrackets == NULL)
2265 		matchbrackets = copy_of("(<[{)>]}");
2266 
2267 	/* If the whitespace option wasn't specified, set its default value. */
2268 	if (whitespace == NULL) {
2269 #ifdef ENABLE_UTF8
2270 		if (using_utf8()) {
2271 			/* A tab is shown as a Right-Pointing Double Angle Quotation Mark
2272 			 * (U+00BB), and a space as a Middle Dot (U+00B7). */
2273 			whitespace = copy_of("\xC2\xBB\xC2\xB7");
2274 			whitelen[0] = 2;
2275 			whitelen[1] = 2;
2276 		} else
2277 #endif
2278 		{
2279 			whitespace = copy_of(">.");
2280 			whitelen[0] = 1;
2281 			whitelen[1] = 1;
2282 		}
2283 	}
2284 #endif /* !NANO_TINY */
2285 
2286 	/* Initialize the search string. */
2287 	last_search = copy_of("");
2288 	UNSET(BACKWARDS_SEARCH);
2289 
2290 	/* If tabsize wasn't specified, set its default value. */
2291 	if (tabsize == -1)
2292 		tabsize = WIDTH_OF_TAB;
2293 
2294 #ifdef ENABLE_COLOR
2295 	/* On capable terminals, use colors, otherwise just reverse or bold.*/
2296 	if (has_colors())
2297 		set_interface_colorpairs();
2298 	else
2299 #endif
2300 	{
2301 		interface_color_pair[TITLE_BAR] = hilite_attribute;
2302 		interface_color_pair[LINE_NUMBER] = hilite_attribute;
2303 		interface_color_pair[GUIDE_STRIPE] = A_REVERSE;
2304 		interface_color_pair[SCROLL_BAR] = A_NORMAL;
2305 		interface_color_pair[SELECTED_TEXT] = hilite_attribute;
2306 		interface_color_pair[SPOTLIGHTED] = A_REVERSE;
2307 		interface_color_pair[MINI_INFOBAR] = hilite_attribute;
2308 		interface_color_pair[PROMPT_BAR] = hilite_attribute;
2309 		interface_color_pair[STATUS_BAR] = hilite_attribute;
2310 		interface_color_pair[ERROR_MESSAGE] = hilite_attribute;
2311 		interface_color_pair[KEY_COMBO] = hilite_attribute;
2312 		interface_color_pair[FUNCTION_TAG] = A_NORMAL;
2313 	}
2314 
2315 	/* Set up the terminal state. */
2316 	terminal_init();
2317 
2318 	/* Create the three subwindows, based on the current screen dimensions. */
2319 	window_init();
2320 	curs_set(0);
2321 
2322 #ifndef NANO_TINY
2323 	thebar = (ISSET(INDICATOR) && LINES > 5 && COLS > 9) ? 1 : 0;
2324 	bardata = nrealloc(bardata, LINES * sizeof(int));
2325 #endif
2326 	editwincols = COLS - thebar;
2327 
2328 	/* Set up the signal handlers. */
2329 	signal_init();
2330 
2331 #ifdef ENABLE_MOUSE
2332 	/* Initialize mouse support. */
2333 	mouse_init();
2334 #endif
2335 
2336 	/* Ask ncurses for the key codes for most modified editing keys. */
2337 	controlleft = get_keycode("kLFT5", CONTROL_LEFT);
2338 	controlright = get_keycode("kRIT5", CONTROL_RIGHT);
2339 	controlup = get_keycode("kUP5", CONTROL_UP);
2340 	controldown = get_keycode("kDN5", CONTROL_DOWN);
2341 
2342 	controlhome = get_keycode("kHOM5", CONTROL_HOME);
2343 	controlend = get_keycode("kEND5", CONTROL_END);
2344 #ifndef NANO_TINY
2345 	controldelete = get_keycode("kDC5", CONTROL_DELETE);
2346 	controlshiftdelete = get_keycode("kDC6", CONTROL_SHIFT_DELETE);
2347 
2348 	shiftup = get_keycode("kUP", SHIFT_UP);
2349 	shiftdown = get_keycode("kDN", SHIFT_DOWN);
2350 
2351 	shiftcontrolleft = get_keycode("kLFT6", SHIFT_CONTROL_LEFT);
2352 	shiftcontrolright = get_keycode("kRIT6", SHIFT_CONTROL_RIGHT);
2353 	shiftcontrolup = get_keycode("kUP6", SHIFT_CONTROL_UP);
2354 	shiftcontroldown = get_keycode("kDN6", SHIFT_CONTROL_DOWN);
2355 
2356 	shiftcontrolhome = get_keycode("kHOM6", SHIFT_CONTROL_HOME);
2357 	shiftcontrolend = get_keycode("kEND6", SHIFT_CONTROL_END);
2358 
2359 	altleft = get_keycode("kLFT3", ALT_LEFT);
2360 	altright = get_keycode("kRIT3", ALT_RIGHT);
2361 	altup = get_keycode("kUP3", ALT_UP);
2362 	altdown = get_keycode("kDN3", ALT_DOWN);
2363 
2364 	altpageup = get_keycode("kPRV3", ALT_PAGEUP);
2365 	altpagedown = get_keycode("kNXT3", ALT_PAGEDOWN);
2366 	altinsert = get_keycode("kIC3", ALT_INSERT);
2367 	altdelete = get_keycode("kDC3", ALT_DELETE);
2368 
2369 	shiftaltleft = get_keycode("kLFT4", SHIFT_ALT_LEFT);
2370 	shiftaltright = get_keycode("kRIT4", SHIFT_ALT_RIGHT);
2371 	shiftaltup = get_keycode("kUP4", SHIFT_ALT_UP);
2372 	shiftaltdown = get_keycode("kDN4", SHIFT_ALT_DOWN);
2373 #endif
2374 
2375 #ifdef HAVE_SET_ESCDELAY
2376 	/* Tell ncurses to pass the Esc key quickly. */
2377 	set_escdelay(50);
2378 #endif
2379 
2380 	/* Read the files mentioned on the command line into new buffers. */
2381 	while (optind < argc && (!openfile || read_them_all)) {
2382 		ssize_t givenline = 0, givencol = 0;
2383 #ifndef NANO_TINY
2384 		char *searchstring = NULL;
2385 #endif
2386 		/* If there's a +LINE[,COLUMN] argument here, eat it up. */
2387 		if (optind < argc - 1 && argv[optind][0] == '+') {
2388 #ifndef NANO_TINY
2389 			int n = 1;
2390 
2391 			while (isalpha(argv[optind][n])) {
2392 				switch (argv[optind][n++]) {
2393 					case 'c': SET(CASE_SENSITIVE); break;
2394 					case 'C': UNSET(CASE_SENSITIVE); break;
2395 					case 'r': SET(USE_REGEXP); break;
2396 					case 'R': UNSET(USE_REGEXP); break;
2397 					default:
2398 						statusline(ALERT, _("Invalid search modifier '%c'"),
2399 											argv[optind][n - 1]);
2400 				}
2401 			}
2402 
2403 			if (argv[optind][n] == '/' || argv[optind][n] == '?') {
2404 				if (argv[optind][n + 1]) {
2405 					searchstring = copy_of(&argv[optind][n + 1]);
2406 					if (argv[optind][n] == '?')
2407 						SET(BACKWARDS_SEARCH);
2408 				} else if (n == 1)
2409 					statusline(ALERT, _("Empty search string"));
2410 				optind++;
2411 			} else
2412 #endif
2413 			/* When there is nothing after the "+", understand it as go-to-EOF,
2414 			 * otherwise parse and store the given number(s).*/
2415 			if (argv[optind++][1] == '\0')
2416 				givenline = -1;
2417 			else if (!parse_line_column(&argv[optind - 1][1], &givenline, &givencol))
2418 				statusline(ALERT, _("Invalid line or column number"));
2419 		}
2420 
2421 #ifndef NANO_TINY
2422 		/* If the filename is a dash, read from standard input; otherwise,
2423 		 * open the file; skip positioning the cursor if either failed. */
2424 		if (strcmp(argv[optind], "-") == 0) {
2425 			optind++;
2426 			if (!scoop_stdin())
2427 				continue;
2428 		} else
2429 #endif
2430 		 if (!open_buffer(argv[optind++], TRUE))
2431 			continue;
2432 
2433 		/* If a position was given on the command line, go there. */
2434 		if (givenline != 0 || givencol != 0)
2435 			do_gotolinecolumn(givenline, givencol, FALSE, FALSE);
2436 #ifndef NANO_TINY
2437 		else if (searchstring != NULL) {
2438 			if (ISSET(USE_REGEXP))
2439 				regexp_init(searchstring);
2440 			if (!findnextstr(searchstring, FALSE, JUSTFIND, NULL,
2441 							ISSET(BACKWARDS_SEARCH), openfile->filetop, 0))
2442 				not_found_msg(searchstring);
2443 			else if (lastmessage <= REMARK)
2444 				wipe_statusbar();
2445 			openfile->placewewant = xplustabs();
2446 			if (ISSET(USE_REGEXP))
2447 				tidy_up_after_search();
2448 			free(last_search);
2449 			last_search = searchstring;
2450 			searchstring = NULL;
2451 		}
2452 #endif
2453 #ifdef ENABLE_HISTORIES
2454 		else if (ISSET(POSITIONLOG) && openfile->filename[0] != '\0') {
2455 			ssize_t savedline, savedcol;
2456 			/* If edited before, restore the last cursor position. */
2457 			if (has_old_position(argv[optind - 1], &savedline, &savedcol))
2458 				do_gotolinecolumn(savedline, savedcol, FALSE, FALSE);
2459 		}
2460 #endif
2461 	}
2462 
2463 	/* If no filenames were given, or all of them were invalid things like
2464 	 * directories, then open a blank buffer and allow editing.  Otherwise,
2465 	 * switch from the last opened file to the next, that is: the first. */
2466 	if (openfile == NULL) {
2467 		open_buffer("", TRUE);
2468 		UNSET(VIEW_MODE);
2469 	}
2470 #ifdef ENABLE_MULTIBUFFER
2471 	else {
2472 		openfile = openfile->next;
2473 		if (more_than_one)
2474 			mention_name_and_linecount();
2475 		if (ISSET(VIEW_MODE))
2476 			SET(MULTIBUFFER);
2477 	}
2478 #else
2479 	if (optind < argc)
2480 		die(_("Can open just one file\n"));
2481 #endif
2482 
2483 	prepare_for_display();
2484 
2485 #ifdef ENABLE_NANORC
2486 	if (startup_problem != NULL)
2487 		statusline(ALERT, startup_problem);
2488 
2489 #define NOTREBOUND  first_sc_for(MMAIN, do_help) && \
2490 						first_sc_for(MMAIN, do_help)->keycode == 0x07
2491 #else
2492 #define NOTREBOUND  TRUE
2493 #endif
2494 
2495 #ifdef ENABLE_HELP
2496 	if (*openfile->filename == '\0' && openfile->totsize == 0 &&
2497 				openfile->next == openfile && !ISSET(NO_HELP) && NOTREBOUND)
2498 		statusbar(_("Welcome to nano.  For basic help, type Ctrl+G."));
2499 #endif
2500 
2501 	we_are_running = TRUE;
2502 
2503 	while (TRUE) {
2504 #ifdef ENABLE_LINENUMBERS
2505 		confirm_margin();
2506 #endif
2507 #ifdef __linux__
2508 		if (on_a_vt && get_key_buffer_len() == 0)
2509 			mute_modifiers = FALSE;
2510 #endif
2511 		if (currmenu != MMAIN)
2512 			bottombars(MMAIN);
2513 
2514 #ifndef NANO_TINY
2515 		if (ISSET(MINIBAR) && LINES > 1 && lastmessage < REMARK)
2516 			minibar();
2517 		else
2518 #endif
2519 		/* Update the displayed current cursor position only when there
2520 		 * is no message and no keys are waiting in the input buffer. */
2521 		if (ISSET(CONSTANT_SHOW) && lastmessage == VACUUM && LINES > 1 &&
2522 										get_key_buffer_len() == 0)
2523 			report_cursor_position();
2524 
2525 		as_an_at = TRUE;
2526 
2527 		/* Refresh just the cursor position or the entire edit window. */
2528 		if (!refresh_needed) {
2529 			place_the_cursor();
2530 			wnoutrefresh(edit);
2531 		} else if (LINES > 1 || lastmessage == VACUUM)
2532 			edit_refresh();
2533 
2534 		errno = 0;
2535 		focusing = TRUE;
2536 
2537 		/* Forget any earlier cursor position at the prompt. */
2538 		put_cursor_at_end_of_answer();
2539 
2540 		/* Read in and interpret a single keystroke. */
2541 		process_a_keystroke();
2542 	}
2543 }
2544