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("ereg, quotestr, NANO_REG_EXTENDED); 2345 if (quoterc != 0) { 2346 size_t size = regerror(quoterc, "ereg, NULL, 0); 2347 char *message = nmalloc(size); 2348 2349 regerror(quoterc, "ereg, 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 }