nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

nano.c (72289B)


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