-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnano.c
2520 lines (2250 loc) · 65.1 KB
/
nano.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**************************************************************************
* nano.c -- This file is part of GNU nano. *
* *
* Copyright (C) 1999-2011, 2013-2020 Free Software Foundation, Inc. *
* Copyright (C) 2014-2020 Benno Schulenberg *
* *
* GNU nano is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation, either version 3 of the License, *
* or (at your option) any later version. *
* *
* GNU nano is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty *
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see http://www.gnu.org/licenses/. *
* *
**************************************************************************/
#include "prototypes.h"
#include "revision.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#if defined(__linux__) || !defined(NANO_TINY)
#include <sys/ioctl.h>
#endif
#ifdef ENABLE_UTF8
#include <langinfo.h>
#endif
#include <locale.h>
#include <string.h>
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#include <unistd.h>
#ifdef __linux__
#include <sys/vt.h>
#endif
#ifdef ENABLE_MULTIBUFFER
#define read_them_all TRUE
#else
#define read_them_all FALSE
#endif
#ifdef ENABLE_MOUSE
static int oldinterval = -1;
/* Used to store the user's original mouse click interval. */
#endif
#ifdef HAVE_TERMIOS_H
static struct termios original_state;
/* The original settings of the user's terminal. */
#else
# define tcsetattr(...)
# define tcgetattr(...)
#endif
static struct sigaction oldaction, newaction;
/* Containers for the original and the temporary handler for SIGINT. */
#ifdef USE_SLANG
static bool selfinduced = FALSE;
/* Whether a suspension was caused from inside nano or from outside. */
#endif
/* Create a new linestruct node. Note that we do not set prevnode->next. */
linestruct *make_new_node(linestruct *prevnode)
{
linestruct *newnode = nmalloc(sizeof(linestruct));
newnode->prev = prevnode;
newnode->next = NULL;
newnode->data = NULL;
#ifdef ENABLE_COLOR
newnode->multidata = NULL;
#endif
newnode->lineno = (prevnode) ? prevnode->lineno + 1 : 1;
#ifndef NANO_TINY
newnode->extrarows = -2; /* Bad value, to make it easier to find bugs. */
newnode->has_anchor = FALSE;
#endif
return newnode;
}
/* Splice a new node into an existing linked list of linestructs. */
void splice_node(linestruct *afterthis, linestruct *newnode)
{
newnode->next = afterthis->next;
newnode->prev = afterthis;
if (afterthis->next != NULL)
afterthis->next->prev = newnode;
afterthis->next = newnode;
/* Update filebot when inserting a node at the end of file. */
if (openfile && openfile->filebot == afterthis)
openfile->filebot = newnode;
}
/* Free the data structures in the given node. */
void delete_node(linestruct *line)
{
#ifdef ENABLE_WRAPPING
/* If the spill-over line for hard-wrapping is deleted... */
if (line == openfile->spillage_line)
openfile->spillage_line = NULL;
#endif
free(line->data);
#ifdef ENABLE_COLOR
free(line->multidata);
#endif
free(line);
}
/* Disconnect a node from a linked list of linestructs and delete it. */
void unlink_node(linestruct *line)
{
if (line->prev != NULL)
line->prev->next = line->next;
if (line->next != NULL)
line->next->prev = line->prev;
/* Update filebot when removing a node at the end of file. */
if (openfile && openfile->filebot == line)
openfile->filebot = line->prev;
delete_node(line);
}
/* Free an entire linked list of linestructs. */
void free_lines(linestruct *src)
{
if (src == NULL)
return;
while (src->next != NULL) {
src = src->next;
delete_node(src->prev);
}
delete_node(src);
}
/* Make a copy of a linestruct node. */
linestruct *copy_node(const linestruct *src)
{
linestruct *dst = nmalloc(sizeof(linestruct));
dst->data = copy_of(src->data);
#ifdef ENABLE_COLOR
dst->multidata = NULL;
#endif
dst->lineno = src->lineno;
#ifndef NANO_TINY
dst->extrarows = src->extrarows;
dst->has_anchor = FALSE;
#endif
return dst;
}
/* Duplicate an entire linked list of linestructs. */
linestruct *copy_buffer(const linestruct *src)
{
linestruct *head, *item;
head = copy_node(src);
head->prev = NULL;
item = head;
src = src->next;
while (src != NULL) {
item->next = copy_node(src);
item->next->prev = item;
item = item->next;
src = src->next;
}
item->next = NULL;
return head;
}
/* Renumber the lines in a buffer, from the given line onwards. */
void renumber_from(linestruct *line)
{
ssize_t number = (line->prev == NULL) ? 0 : line->prev->lineno;
while (line != NULL) {
line->lineno = ++number;
line = line->next;
}
}
/* Display a warning about a key disabled in view mode. */
void print_view_warning(void)
{
statusbar(_("Key is invalid in view mode"));
}
/* When in restricted mode, show a warning and return TRUE. */
bool in_restricted_mode(void)
{
if (ISSET(RESTRICTED)) {
statusbar(_("This function is disabled in restricted mode"));
beep();
return TRUE;
} else
return FALSE;
}
#ifndef ENABLE_HELP
/* Indicate that help texts are unavailable. */
void say_there_is_no_help(void)
{
statusbar(_("Help is not available"));
}
#endif
/* Make sure the cursor is visible, then exit from curses mode, disable
* bracketed-paste mode, and restore the original terminal settings. */
void restore_terminal(void)
{
curs_set(1);
endwin();
#ifndef NANO_TINY
printf("\x1B[?2004l");
fflush(stdout);
#endif
tcsetattr(0, TCSANOW, &original_state);
}
/* Exit normally: restore terminal state and report any startup errors. */
void finish(void)
{
/* Blank the status bar and (if applicable) the shortcut list. */
blank_statusbar();
blank_bottombars();
wrefresh(bottomwin);
#ifndef NANO_TINY
/* Deallocate the two or three subwindows. */
if (topwin != NULL)
delwin(topwin);
delwin(edit);
delwin(bottomwin);
#endif
/* Switch the cursor on, exit from curses, and restore terminal settings. */
restore_terminal();
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
display_rcfile_errors();
#endif
/* Get out. */
exit(0);
}
/* Close the current buffer, and terminate nano if it is the only buffer. */
void close_and_go(void)
{
#ifndef NANO_TINY
if (openfile->lock_filename)
delete_lockfile(openfile->lock_filename);
#endif
#ifdef ENABLE_HISTORIES
if (ISSET(POSITIONLOG))
update_poshistory();
#endif
#ifdef ENABLE_MULTIBUFFER
/* If there is another buffer, close this one; otherwise just terminate. */
if (openfile != openfile->next) {
switch_to_next_buffer();
openfile = openfile->prev;
close_buffer();
openfile = openfile->next;
/* Adjust the count in the top bar. */
titlebar(NULL);
} else
#endif
{
#ifdef ENABLE_HISTORIES
if (ISSET(HISTORYLOG))
save_history();
#endif
finish();
}
}
/* Close the current buffer if it is unmodified; otherwise (when not doing
* automatic saving), ask the user whether to save it, then close it and
* exit, or return when the user cancelled. */
void do_exit(void)
{
int choice;
/* When unmodified, simply close. Else, when doing automatic saving
* and the file has a name, simply save. Otherwise, ask the user. */
if (!openfile->modified)
choice = 0;
else if (ISSET(SAVE_ON_EXIT) && openfile->filename[0] != '\0')
choice = 1;
else {
if (ISSET(SAVE_ON_EXIT))
warn_and_briefly_pause(_("No file name"));
choice = do_yesno_prompt(FALSE, _("Save modified buffer? "));
}
/* When not saving, or the save succeeds, close the buffer. */
if (choice == 0 || (choice == 1 && do_writeout(TRUE, TRUE) > 0))
close_and_go();
else if (choice != 1)
statusbar(_("Cancelled"));
}
/* Save the current buffer under the given name (or under the name "nano"
* for a nameless buffer). If needed, the name is modified to be unique. */
void emergency_save(const char *plainname)
{
bool failed = TRUE;
char *targetname;
if (*plainname == '\0')
plainname = "nano";
targetname = get_next_filename(plainname, ".save");
if (*targetname != '\0')
failed = !write_file(targetname, NULL, TRUE, OVERWRITE, FALSE);
if (!failed)
fprintf(stderr, _("\nBuffer written to %s\n"), targetname);
else if (*targetname != '\0')
fprintf(stderr, _("\nBuffer not written to %s: %s\n"),
targetname, strerror(errno));
else
fprintf(stderr, _("\nToo many .save files"));
#ifndef NANO_TINY
/* Try to chmod/chown the saved file to the values of the original file,
* but ignore any failure as we are in a hurry to get out. */
if (openfile->statinfo) {
IGNORE_CALL_RESULT(chmod(targetname, openfile->statinfo->st_mode));
IGNORE_CALL_RESULT(chown(targetname, openfile->statinfo->st_uid,
openfile->statinfo->st_gid));
}
#endif
free(targetname);
}
/* Die gracefully -- by restoring the terminal state and saving any buffers
* that were modified. */
void die(const char *msg, ...)
{
va_list ap;
openfilestruct *firstone = openfile;
restore_terminal();
#ifdef ENABLE_NANORC
display_rcfile_errors();
#endif
/* Display the dying message. */
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
while (openfile) {
#ifndef NANO_TINY
/* If the current buffer has a lockfile, remove it. */
if (openfile->lock_filename)
delete_lockfile(openfile->lock_filename);
#endif
/* When modified, save the current buffer. But not when in restricted
* mode, as it would write a file not mentioned on the command line. */
if (openfile->modified && !ISSET(RESTRICTED))
emergency_save(openfile->filename);
#ifdef ENABLE_MULTIBUFFER
openfile = openfile->next;
#endif
if (openfile == firstone)
break;
}
/* Abandon the building. */
exit(1);
}
/* Initialize the three window portions nano uses. */
void window_init(void)
{
/* When resizing, first delete the existing windows. */
if (edit != NULL) {
if (topwin != NULL)
delwin(topwin);
delwin(edit);
delwin(bottomwin);
}
/* If the terminal is very flat, don't set up a title bar. */
if (LINES < 3) {
topwin = NULL;
editwinrows = 1;
/* Set up two subwindows. If the terminal is just one line,
* edit window and status-bar window will cover each other. */
edit = newwin(1, COLS, 0, 0);
bottomwin = newwin(1, COLS, LINES - 1, 0);
} else {
int toprows = (!ISSET(EMPTY_LINE) ? 1 : (LINES < 6) ? 1 : 2);
int bottomrows = (ISSET(NO_HELP) ? 1 : (LINES < 5) ? 1 : 3);
editwinrows = LINES - toprows - bottomrows;
/* Set up the normal three subwindows. */
topwin = newwin(toprows, COLS, 0, 0);
edit = newwin(editwinrows, COLS, toprows, 0);
bottomwin = newwin(bottomrows, COLS, toprows + editwinrows, 0);
}
/* In case the terminal shrunk, make sure the status line is clear. */
wipe_statusbar();
/* When not disabled, turn escape-sequence translation on. */
if (!ISSET(RAW_SEQUENCES)) {
keypad(edit, TRUE);
keypad(bottomwin, TRUE);
}
#ifdef ENABLED_WRAPORJUSTIFY
/* Set up the wrapping point, accounting for screen width when negative. */
if (COLS + fill < 0)
wrap_at = 0;
else if (fill <= 0)
wrap_at = COLS + fill;
else
wrap_at = fill;
#endif
}
#ifdef ENABLE_MOUSE
void disable_mouse_support(void)
{
mousemask(0, NULL);
mouseinterval(oldinterval);
}
void enable_mouse_support(void)
{
mousemask(ALL_MOUSE_EVENTS, NULL);
oldinterval = mouseinterval(50);
}
/* Switch mouse support on or off, as needed. */
void mouse_init(void)
{
if (ISSET(USE_MOUSE))
enable_mouse_support();
else
disable_mouse_support();
}
#endif /* ENABLE_MOUSE */
/* Print the usage line for the given option to the screen. */
void print_opt(const char *shortflag, const char *longflag, const char *desc)
{
int firstwidth = breadth(shortflag);
int secondwidth = breadth(longflag);
printf(" %s", shortflag);
if (firstwidth < 14)
printf("%*s", 14 - firstwidth, " ");
printf(" %s", longflag);
if (secondwidth < 24)
printf("%*s", 24 - secondwidth, " ");
printf("%s\n", _(desc));
}
/* Explain how to properly use nano and its command-line options. */
void usage(void)
{
printf(_("Usage: nano [OPTIONS] [[+LINE[,COLUMN]] FILE]...\n\n"));
/* TRANSLATORS: The next two strings are part of the --help output.
* It's best to keep its lines within 80 characters. */
printf(_("To place the cursor on a specific line of a file, put the line number with\n"
"a '+' before the filename. The column number can be added after a comma.\n"));
printf(_("When a filename is '-', nano reads data from standard input.\n\n"));
/* TRANSLATORS: The next three are column headers of the --help output. */
print_opt(_("Option"), _("Long option"), N_("Meaning"));
#ifndef NANO_TINY
/* TRANSLATORS: The next forty or so strings are option descriptions
* for the --help output. Try to keep them at most 40 characters. */
print_opt("-A", "--smarthome", N_("Enable smart home key"));
if (!ISSET(RESTRICTED)) {
print_opt("-B", "--backup", N_("Save backups of existing files"));
print_opt(_("-C <dir>"), _("--backupdir=<dir>"),
N_("Directory for saving unique backup files"));
}
#endif
print_opt("-D", "--boldtext", N_("Use bold instead of reverse video text"));
#ifndef NANO_TINY
print_opt("-E", "--tabstospaces", N_("Convert typed tabs to spaces"));
#endif
#ifdef ENABLE_MULTIBUFFER
if (!ISSET(RESTRICTED))
print_opt("-F", "--multibuffer",
N_("Read a file into a new buffer by default"));
#endif
#ifndef NANO_TINY
print_opt("-G", "--locking", N_("Use (vim-style) lock files"));
#endif
#ifdef ENABLE_HISTORIES
if (!ISSET(RESTRICTED))
print_opt("-H", "--historylog",
N_("Log & read search/replace string history"));
#endif
#ifdef ENABLE_NANORC
print_opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
#endif
#ifndef NANO_TINY
print_opt(_("-J <number>"), _("--guidestripe=<number>"),
N_("Show a guiding bar at this column"));
#endif
print_opt("-K", "--rawsequences",
N_("Fix numeric keypad key confusion problem"));
#ifndef NANO_TINY
print_opt("-L", "--nonewlines",
N_("Don't add an automatic newline"));
#endif
#ifdef ENABLED_WRAPORJUSTIFY
print_opt("-M", "--trimblanks",
N_("Trim tail spaces when hard-wrapping"));
#endif
#ifndef NANO_TINY
print_opt("-N", "--noconvert",
N_("Don't convert files from DOS/Mac format"));
print_opt("-O", "--bookstyle",
N_("Leading whitespace means new paragraph"));
#endif
#ifdef ENABLE_HISTORIES
if (!ISSET(RESTRICTED))
print_opt("-P", "--positionlog",
N_("Log & read location of cursor position"));
#endif
#ifdef ENABLE_JUSTIFY
print_opt(_("-Q <regex>"), _("--quotestr=<regex>"),
/* TRANSLATORS: This refers to email quoting,
* like the > in: > quoted text. */
N_("Regular expression to match quoting"));
#endif
if (!ISSET(RESTRICTED))
print_opt("-R", "--restricted", N_("Restrict access to the filesystem"));
#ifndef NANO_TINY
print_opt("-S", "--softwrap", N_("Display overlong lines on multiple rows"));
#endif
print_opt(_("-T <number>"), _("--tabsize=<number>"),
N_("Make a tab this number of columns wide"));
print_opt("-U", "--quickblank", N_("Wipe status bar upon next keystroke"));
print_opt("-V", "--version", N_("Print version information and exit"));
#ifndef NANO_TINY
print_opt("-W", "--wordbounds",
N_("Detect word boundaries more accurately"));
print_opt(_("-X <string>"), _("--wordchars=<string>"),
N_("Which other characters are word parts"));
#endif
#ifdef ENABLE_COLOR
if (!ISSET(RESTRICTED))
print_opt(_("-Y <name>"), _("--syntax=<name>"),
N_("Syntax definition to use for coloring"));
#endif
#ifndef NANO_TINY
print_opt("-Z", "--zap", N_("Let Bsp and Del erase a marked region"));
print_opt("-a", "--atblanks", N_("When soft-wrapping, do it at whitespace"));
#endif
#ifdef ENABLE_WRAPPING
print_opt("-b", "--breaklonglines", N_("Automatically hard-wrap overlong lines"));
#endif
print_opt("-c", "--constantshow", N_("Constantly show cursor position"));
print_opt("-d", "--rebinddelete",
N_("Fix Backspace/Delete confusion problem"));
print_opt("-e", "--emptyline", N_("Keep the line below the title bar empty"));
#ifdef ENABLE_NANORC
print_opt(_("-f <file>"), _("--rcfile=<file>"),
N_("Use only this file for configuring nano"));
#endif
#if defined(ENABLE_BROWSER) || defined(ENABLE_HELP)
print_opt("-g", "--showcursor", N_("Show cursor in file browser & help text"));
#endif
print_opt("-h", "--help", N_("Show this help text and exit"));
#ifndef NANO_TINY
print_opt("-i", "--autoindent", N_("Automatically indent new lines"));
#endif
print_opt("-j", "--jumpyscrolling", N_("Scroll per half-screen, not per line"));
#ifndef NANO_TINY
print_opt("-k", "--cutfromcursor", N_("Cut from cursor to end of line"));
#endif
#ifdef ENABLE_LINENUMBERS
print_opt("-l", "--linenumbers", N_("Show line numbers in front of the text"));
#endif
#ifdef ENABLE_MOUSE
print_opt("-m", "--mouse", N_("Enable the use of the mouse"));
#endif
print_opt("-n", "--noread", N_("Do not read the file (only write it)"));
#ifdef ENABLE_OPERATINGDIR
print_opt(_("-o <dir>"), _("--operatingdir=<dir>"),
N_("Set operating directory"));
#endif
print_opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
#ifndef NANO_TINY
print_opt("-q", "--indicator", N_("Show a position+portion indicator"));
#endif
#ifdef ENABLED_WRAPORJUSTIFY
print_opt(_("-r <number>"), _("--fill=<number>"),
N_("Set width for hard-wrap and justify"));
#endif
#ifdef ENABLE_SPELLER
if (!ISSET(RESTRICTED))
print_opt(_("-s <program>"), _("--speller=<program>"),
N_("Use this alternative spell checker"));
#endif
print_opt("-t", "--saveonexit", N_("Save changes on exit, don't prompt"));
#ifndef NANO_TINY
print_opt("-u", "--unix", N_("Save a file by default in Unix format"));
#endif
print_opt("-v", "--view", N_("View mode (read-only)"));
#ifdef ENABLE_WRAPPING
print_opt("-w", "--nowrap", N_("Don't hard-wrap long lines [default]"));
#endif
print_opt("-x", "--nohelp", N_("Don't show the two help lines"));
#ifndef NANO_TINY
print_opt("-y", "--afterends", N_("Make Ctrl+Right stop at word ends"));
#endif
if (!ISSET(RESTRICTED))
print_opt("-z", "--suspendable", N_("Enable suspension"));
}
/* Display the current version of nano, the date and time it was
* compiled, contact information for it, and the configuration options
* it was compiled with. */
void version(void)
{
#ifdef REVISION
printf(" GNU nano from git, %s\n", REVISION);
#else
printf(_(" GNU nano, version %s\n"), VERSION);
#endif
printf(" (C) 1999-2011, 2013-2020 Free Software Foundation, Inc.\n");
printf(_(" (C) 2014-%s the contributors to nano\n"), "2020");
printf(_(" Email: [email protected] Web: https://nano-editor.org/"));
printf(_("\n Compiled options:"));
#ifdef NANO_TINY
printf(" --enable-tiny");
#ifdef ENABLE_BROWSER
printf(" --enable-browser");
#endif
#ifdef ENABLE_COLOR
printf(" --enable-color");
#endif
#ifdef ENABLE_EXTRA
printf(" --enable-extra");
#endif
#ifdef ENABLE_HELP
printf(" --enable-help");
#endif
#ifdef ENABLE_HISTORIES
printf(" --enable-histories");
#endif
#ifdef ENABLE_JUSTIFY
printf(" --enable-justify");
#endif
#ifdef HAVE_LIBMAGIC
printf(" --enable-libmagic");
#endif
#ifdef ENABLE_LINENUMBERS
printf(" --enable-linenumbers");
#endif
#ifdef ENABLE_MOUSE
printf(" --enable-mouse");
#endif
#ifdef ENABLE_NANORC
printf(" --enable-nanorc");
#endif
#ifdef ENABLE_MULTIBUFFER
printf(" --enable-multibuffer");
#endif
#ifdef ENABLE_OPERATINGDIR
printf(" --enable-operatingdir");
#endif
#ifdef ENABLE_SPELLER
printf(" --enable-speller");
#endif
#ifdef ENABLE_TABCOMP
printf(" --enable-tabcomp");
#endif
#ifdef ENABLE_WRAPPING
printf(" --enable-wrapping");
#endif
#else /* !NANO_TINY */
#ifndef ENABLE_BROWSER
printf(" --disable-browser");
#endif
#ifndef ENABLE_COLOR
printf(" --disable-color");
#endif
#ifndef ENABLE_COMMENT
printf(" --disable-comment");
#endif
#ifndef ENABLE_EXTRA
printf(" --disable-extra");
#endif
#ifndef ENABLE_HELP
printf(" --disable-help");
#endif
#ifndef ENABLE_HISTORIES
printf(" --disable-histories");
#endif
#ifndef ENABLE_JUSTIFY
printf(" --disable-justify");
#endif
#ifndef HAVE_LIBMAGIC
printf(" --disable-libmagic");
#endif
#ifndef ENABLE_LINENUMBERS
printf(" --disable-linenumbers");
#endif
#ifndef ENABLE_MOUSE
printf(" --disable-mouse");
#endif
#ifndef ENABLE_MULTIBUFFER
printf(" --disable-multibuffer");
#endif
#ifndef ENABLE_NANORC
printf(" --disable-nanorc");
#endif
#ifndef ENABLE_OPERATINGDIR
printf(" --disable-operatingdir");
#endif
#ifndef ENABLE_SPELLER
printf(" --disable-speller");
#endif
#ifndef ENABLE_TABCOMP
printf(" --disable-tabcomp");
#endif
#ifndef ENABLE_WORDCOMPLETION
printf(" --disable-wordcomp");
#endif
#ifndef ENABLE_WRAPPING
printf(" --disable-wrapping");
#endif
#endif /* !NANO_TINY */
#ifdef DEBUG
printf(" --enable-debug");
#endif
#ifndef ENABLE_NLS
printf(" --disable-nls");
#endif
#ifdef ENABLE_UTF8
printf(" --enable-utf8");
#else
printf(" --disable-utf8");
#endif
#ifdef USE_SLANG
printf(" --with-slang");
#endif
printf("\n");
}
/* Register that Ctrl+C was pressed during some system call. */
RETSIGTYPE make_a_note(int signal)
{
control_C_was_pressed = TRUE;
}
/* Make ^C interrupt a system call and set a flag. */
void install_handler_for_Ctrl_C(void)
{
/* Enable the generation of a SIGINT when ^C is pressed. */
enable_kb_interrupt();
/* Set up a signal handler so that pressing ^C will set a flag. */
newaction.sa_handler = make_a_note;
newaction.sa_flags = 0;
sigaction(SIGINT, &newaction, &oldaction);
}
/* Go back to ignoring ^C. */
void restore_handler_for_Ctrl_C(void)
{
sigaction(SIGINT, &oldaction, NULL);
disable_kb_interrupt();
}
/* Reconnect standard input to the tty, and store its state. */
void reconnect_and_store_state(void)
{
int thetty = open("/dev/tty", O_RDONLY);
if (thetty < 1)
die(_("Could not reconnect stdin to keyboard\n"));
dup2(thetty, STANDARD_INPUT);
close(thetty);
/* If input was not cut short, store the current state of the terminal. */
if (!control_C_was_pressed)
tcgetattr(0, &original_state);
}
/* Read whatever comes from standard input into a new buffer. */
bool scoop_stdin(void)
{
FILE *stream;
restore_terminal();
/* When input comes from a terminal, show a helpful message. */
if (isatty(STANDARD_INPUT))
fprintf(stderr, _("Reading data from keyboard; "
"type ^D or ^D^D to finish.\n"));
/* Open standard input. */
stream = fopen("/dev/stdin", "rb");
if (stream == NULL) {
int errnumber = errno;
terminal_init();
doupdate();
statusline(ALERT, _("Failed to open stdin: %s"), strerror(errnumber));
return FALSE;
}
/* Set up a signal handler so that ^C will stop the reading. */
install_handler_for_Ctrl_C();
/* Read the input into a new buffer. */
make_new_buffer();
read_file(stream, 0, "stdin", TRUE);
#ifdef ENABLE_COLOR
find_and_prime_applicable_syntax();
#endif
/* Restore the original ^C handler. */
restore_handler_for_Ctrl_C();
if (!ISSET(VIEW_MODE) && openfile->totsize > 0)
set_modified();
return TRUE;
}
/* Register half a dozen signal handlers. */
void signal_init(void)
{
struct sigaction deed = {{0}};
/* Trap SIGINT and SIGQUIT because we want them to do useful things. */
deed.sa_handler = SIG_IGN;
sigaction(SIGINT, &deed, NULL);
#ifdef SIGQUIT
sigaction(SIGQUIT, &deed, NULL);
#endif
/* Trap SIGHUP and SIGTERM because we want to write the file out. */
deed.sa_handler = handle_hupterm;
#ifdef SIGHUP
sigaction(SIGHUP, &deed, NULL);
#endif
sigaction(SIGTERM, &deed, NULL);
#ifndef NANO_TINY
/* Trap SIGWINCH because we want to handle window resizes. */
deed.sa_handler = handle_sigwinch;
sigaction(SIGWINCH, &deed, NULL);
#endif
/* In the suspend and continue handlers, block all other signals.
* If we don't do this, other stuff interrupts them! */
sigfillset(&deed.sa_mask);
#ifdef SIGTSTP
deed.sa_handler = do_suspend;
sigaction(SIGTSTP, &deed, NULL);
#endif
#ifdef SIGCONT
deed.sa_handler = do_continue;
sigaction(SIGCONT, &deed, NULL);
#endif
#if !defined(NANO_TINY) && !defined(DEBUG)
if (getenv("NANO_NOCATCH") == NULL) {
/* Trap SIGSEGV and SIGABRT to save any changed buffers and reset
* the terminal to a usable state. Reset these handlers to their
* defaults as soon as their signal fires. */
deed.sa_handler = handle_crash;
deed.sa_flags |= SA_RESETHAND;
sigaction(SIGSEGV, &deed, NULL);
sigaction(SIGABRT, &deed, NULL);
}
#endif
}
/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
RETSIGTYPE handle_hupterm(int signal)
{
die(_("Received SIGHUP or SIGTERM\n"));
}
#if !defined(NANO_TINY) && !defined(DEBUG)
/* Handler for SIGSEGV (segfault) and SIGABRT (abort). */
RETSIGTYPE handle_crash(int signal)
{
die(_("Sorry! Nano crashed! Code: %d. Please report a bug.\n"), signal);
}
#endif
/* Handler for SIGTSTP (suspend). */
RETSIGTYPE do_suspend(int signal)
{
#ifdef ENABLE_MOUSE
disable_mouse_support();
#endif
restore_terminal();
printf("\n\n");
/* Display our helpful message. */
printf(_("Use \"fg\" to return to nano.\n"));
fflush(stdout);
/* The suspend keystroke must not elicit cursor-position display. */
lastmessage = HUSH;
#ifdef SIGSTOP
/* Do what mutt does: send ourselves a SIGSTOP. */
kill(0, SIGSTOP);
#endif
}
/* Put nano to sleep (if suspension is enabled). */
void do_suspend_void(void)
{
if (ISSET(SUSPENDABLE)) {
#ifdef USE_SLANG
selfinduced = TRUE;
do_suspend(0);
selfinduced = FALSE;
#else
do_suspend(0);
#endif
} else {
statusbar(_("Suspension is not enabled"));
beep();
}
ran_a_tool = TRUE;
}
/* Handler for SIGCONT (continue after suspend). */
RETSIGTYPE do_continue(int signal)
{
#ifdef ENABLE_MOUSE
if (ISSET(USE_MOUSE))
enable_mouse_support();
#endif
#ifndef NANO_TINY
/* Perhaps the user resized the window while we slept. */
the_window_resized = TRUE;
#else
/* Put the terminal in the desired state again. */
terminal_init();
#endif
#ifdef USE_SLANG
if (!selfinduced)
full_refresh();
#else
/* Insert a fake keystroke, to neutralize a key-eating issue. */
ungetch(KEY_FLUSH);
#endif
}
#if !defined(NANO_TINY) || defined(ENABLE_SPELLER) || defined(ENABLE_COLOR)
/* Block or unblock the SIGWINCH signal, depending on the blockit parameter. */
void block_sigwinch(bool blockit)
{
sigset_t winch;
sigemptyset(&winch);