minor overhaul of terminal-related things

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1745 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
This commit is contained in:
David Lawrence Ramsey 2004-05-18 01:20:36 +00:00
parent 36e363f525
commit d7fd200a6a
6 changed files with 350 additions and 328 deletions

View File

@ -6,6 +6,8 @@ CVS code -
- Make sure the special control keys are handled the same way - Make sure the special control keys are handled the same way
after the window is resized or we come out of suspend mode. after the window is resized or we come out of suspend mode.
Changes to do_cont() and handle_sigwinch(). (DLR) Changes to do_cont() and handle_sigwinch(). (DLR)
- Change some instances of ints that can never be negative to
size_t's. (DLR)
- Add better explanations for and in the "Terminal breakage" - Add better explanations for and in the "Terminal breakage"
comments, and handle missing key #ifdefs inside the functions comments, and handle missing key #ifdefs inside the functions
that use those keys. (DLR) that use those keys. (DLR)
@ -48,6 +50,9 @@ CVS code -
justify_format() may get a space tacked onto the end of it justify_format() may get a space tacked onto the end of it
later, so now the entire original paragraph is always backed later, so now the entire original paragraph is always backed
up.) (DLR) up.) (DLR)
- Wrap the long jump code in NANO_SMALL #ifdefs, since we only
use it if we're resizing the window, which is disabled when
NANO_SMALL is defined. (DLR)
- files.c: - files.c:
add_open_file() add_open_file()
- Rearrange the NANO_SMALL #ifdef so that the code to set the - Rearrange the NANO_SMALL #ifdef so that the code to set the
@ -57,6 +62,15 @@ CVS code -
- Refactor so that no recursion is needed if we try to exit with - Refactor so that no recursion is needed if we try to exit with
a modified file that has no name when TEMP_OPT is set. (DLR) a modified file that has no name when TEMP_OPT is set. (DLR)
- nano.c: - nano.c:
do_toggle(), finish()
- Call blank_statusbar() and blank_bottombars() to blank out
the statusbar and shortcut list in bottomwin. (DLR)
do_early_abort()
- Removed, as it's no longer called anywhere. (David Benbennick)
open_pipe()
- Call enable_signals() at the beginning and disable_signals()
at the end, so that we get a SIGINT when Ctrl-C is pressed
during wait() and can then call cancel_fork() properly. (DLR)
do_delete() do_delete()
- Tweak for efficiency. (David Benbennick) - Tweak for efficiency. (David Benbennick)
justify_format() justify_format()
@ -72,10 +86,32 @@ CVS code -
print_numlock_warning() print_numlock_warning()
- Removed, as it's no longer needed and was never called - Removed, as it's no longer needed and was never called
anywhere after the input overhaul. (DLR) anywhere after the input overhaul. (DLR)
signal_init()
- Don't use termios and _POSIX_VDISABLE to disable keys anymore,
as there's no real equivalent of it when the latter isn't
defined. (DLR)
handle_sigwinch()
- Call resetty() to get the original terminal settings back.
(DLR)
- Rework so that nano properly redraws the screen on systems
that don't have resizeterm() and/or wresize(). In curses, we
now leave and immediately reenter curses mode via endwin() and
refresh(), and then reinitialize all windows via
window_init(). In slang, the above routine will only work if
the resize made the window smaller, so we now leave and
immediately reenter screen management mode via
SLsmg_reset_smg() and SLsmg_init_smg(), and then reinitialize
all windows via window_init(). (DLR, adapted from code in
Minimum Profit 3.3.0 and mutt 1.4.2.1, respectively)
do_verbatim_input() do_verbatim_input()
- Use size_t's instead of ints for the get_verbatim_kbinput() - If PRESERVE is set, disable flow control characters before
call and the loop that ungetch()es its returned int*, getting input and reenable them after getting input. (DLR)
respectively. (DLR) disable_signals(), enable_signals(), disable_flow_control(),
enable_flow_control()
- New functions that allow more fine-grained control of the
terminal: disabling and enabling signals without having to use
_POSIX_VDISABLE and disabling and enabling flow control
characters. (DLR)
main() main()
- Don't open the first file in quiet mode, since if we do, an - Don't open the first file in quiet mode, since if we do, an
error message won't be shown if it's unreadable. (DLR; found error message won't be shown if it's unreadable. (DLR; found
@ -88,6 +124,17 @@ CVS code -
the nanorc first, both of which are unintuitive. Multibuffer the nanorc first, both of which are unintuitive. Multibuffer
mode should only affect how the "Read File" command behaves mode should only affect how the "Read File" command behaves
anyway. (DLR) anyway. (DLR)
- Remove the disabling of implementation-defined input
processing, as raw mode appears to turn it off anyway. (DLR)
- Use raw mode instead of cbreak mode, since it comes closest to
what we need by automatically disabling the special control
keys. (DLR)
- After noecho(), call disable_signals() and
disable_flow_control(), the latter only if PRESERVE is not
set. (DLR)
- Move the savetty() call down from just after initscr() to just
after the terminal is properly set up, so that we can restore
it easily after a resize. (DLR)
- nano.h: - nano.h:
- Since REGEXP_COMPILED is only used in search.c, convert it - Since REGEXP_COMPILED is only used in search.c, convert it
from a flag to a static int there. (DLR) from a flag to a static int there. (DLR)
@ -131,8 +178,6 @@ CVS code -
- Refactor the output in the DEBUG #ifdef. It didn't work - Refactor the output in the DEBUG #ifdef. It didn't work
properly ever since this function was changed to use an int* properly ever since this function was changed to use an int*
instead of a char*. (DLR) instead of a char*. (DLR)
- Change kbinput_len from an int* to a size_t*, since it should
never be negative. (DLR)
- When reading characters from input, properly reallocate - When reading characters from input, properly reallocate
verbatim_kbinput via (int*)nrealloc() instead of an uncast verbatim_kbinput via (int*)nrealloc() instead of an uncast
realloc(). (DLR) realloc(). (DLR)
@ -140,8 +185,6 @@ CVS code -
- Add proper support for the keypad values and escape sequences - Add proper support for the keypad values and escape sequences
generated by the NumLock glitch. (DLR) generated by the NumLock glitch. (DLR)
get_escape_seq_kbinput() get_escape_seq_kbinput()
- Change escape_seq_len from an int to a size_t, since it should
never be negative. (DLR)
- Add proper support for the keypad values and escape sequences - Add proper support for the keypad values and escape sequences
generated by the NumLock glitch. (DLR) generated by the NumLock glitch. (DLR)
bottombars() bottombars()
@ -152,6 +195,14 @@ CVS code -
edit_add() edit_add()
- Minor cosmetic reformatting. Also remove unused int - Minor cosmetic reformatting. Also remove unused int
searched_later_lines. (DLR) searched_later_lines. (DLR)
blank_bottomwin()
- Removed, as it does the same thing as blank_bottombars().
(David Benbennick)
blank_titlebar()
- New function used to blank the titlebar in topwin. (DLR)
bottombars()
- Call blank_bottombars() instead of blank_bottomwin(). (David
Benbennick)
edit_refresh() edit_refresh()
- Remove apparently unneeded leaveok() calls. (David Benbennick) - Remove apparently unneeded leaveok() calls. (David Benbennick)
statusbar() statusbar()
@ -163,6 +214,7 @@ CVS code -
- Use napms() instead of nanosleep(), as it does the same thing - Use napms() instead of nanosleep(), as it does the same thing
(aside from taking an argument in milliseconds instead of (aside from taking an argument in milliseconds instead of
microseconds) and curses includes it. (DLR) microseconds) and curses includes it. (DLR)
- Overhaul for efficiency. (David Benbennick)
- configure.ac: - configure.ac:
- Add tests for isblank() and strcasestr(), and define - Add tests for isblank() and strcasestr(), and define
_GNU_SOURCE so that the tests work properly. Increase the _GNU_SOURCE so that the tests work properly. Increase the
@ -171,6 +223,8 @@ CVS code -
fewer lines than usual, so as to make them easier to read, and fewer lines than usual, so as to make them easier to read, and
remove unnecessary inclusion of stdio.h in the slang test remove unnecessary inclusion of stdio.h in the slang test
programs. (DLR) programs. (DLR)
- Remove the checks for resizeterm() and wresize(), as they're
no longer needed. (DLR)
- faq.html: - faq.html:
- Removed question about the NumLock glitch, as it's no longer - Removed question about the NumLock glitch, as it's no longer
needed. (DLR) needed. (DLR)

View File

@ -105,7 +105,8 @@ void new_file(void)
#endif #endif
} }
filestruct *read_line(char *buf, filestruct *prev, int *line1ins, int len) filestruct *read_line(char *buf, filestruct *prev, int *line1ins, size_t
len)
{ {
filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct)); filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct));
@ -2454,7 +2455,7 @@ int diralphasort(const void *va, const void *vb)
} }
/* Free our malloc()ed memory */ /* Free our malloc()ed memory */
void free_charptrarray(char **array, int len) void free_charptrarray(char **array, size_t len)
{ {
for (; len > 0; len--) for (; len > 0; len--)
free(array[len - 1]); free(array[len - 1]);

View File

@ -25,7 +25,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <signal.h> #include <signal.h>
#include <setjmp.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
@ -54,6 +53,10 @@
#include <getopt.h> #include <getopt.h>
#endif #endif
#ifndef NANO_SMALL
#include <setjmp.h>
#endif
#ifndef DISABLE_WRAPJUSTIFY #ifndef DISABLE_WRAPJUSTIFY
static int fill = 0; /* Fill - where to wrap lines, basically */ static int fill = 0; /* Fill - where to wrap lines, basically */
#endif #endif
@ -65,21 +68,22 @@ static int same_line_wrap = 0; /* Whether wrapped text should be
static struct termios oldterm; /* The user's original term settings */ static struct termios oldterm; /* The user's original term settings */
static struct sigaction act; /* For all our fun signal handlers */ static struct sigaction act; /* For all our fun signal handlers */
#ifndef NANO_SMALL
static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */ static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
#endif
/* What we do when we're all set to exit */ /* What we do when we're all set to exit */
RETSIGTYPE finish(int sigage) RETSIGTYPE finish(int sigage)
{ {
if (!ISSET(NO_HELP)) { if (!ISSET(NO_HELP))
mvwaddstr(bottomwin, 1, 0, hblank); blank_bottombars();
mvwaddstr(bottomwin, 2, 0, hblank); else
} else blank_statusbar();
mvwaddstr(bottomwin, 0, 0, hblank);
wrefresh(bottomwin); wrefresh(bottomwin);
endwin(); endwin();
/* Restore the old term settings */ /* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &oldterm); tcsetattr(0, TCSANOW, &oldterm);
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC) #if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
@ -102,7 +106,7 @@ void die(const char *msg, ...)
endwin(); endwin();
curses_ended = TRUE; curses_ended = TRUE;
/* Restore the old term settings */ /* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &oldterm); tcsetattr(0, TCSANOW, &oldterm);
va_start(ap, msg); va_start(ap, msg);
@ -241,7 +245,7 @@ void window_init(void)
edit = newwin(editwinrows, COLS, 2, 0); edit = newwin(editwinrows, COLS, 2, 0);
bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0); bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
/* Turn the keypad on in the windows we'll be reading input from. */ /* Turn the keypad back on. */
keypad(edit, TRUE); keypad(edit, TRUE);
keypad(bottomwin, TRUE); keypad(bottomwin, TRUE);
} }
@ -758,13 +762,6 @@ void version(void)
printf("\n"); printf("\n");
} }
/* Stuff we do when we abort from programs and want to clean up the
* screen. This doesn't do much right now. */
void do_early_abort(void)
{
blank_statusbar_refresh();
}
int no_help(void) int no_help(void)
{ {
return ISSET(NO_HELP) ? 2 : 0; return ISSET(NO_HELP) ? 2 : 0;
@ -792,13 +789,10 @@ int open_pipe(const char *command)
FILE *f; FILE *f;
struct sigaction oldaction, newaction; struct sigaction oldaction, newaction;
/* original and temporary handlers for SIGINT */ /* original and temporary handlers for SIGINT */
#ifdef _POSIX_VDISABLE
struct termios term, newterm;
#endif /* _POSIX_VDISABLE */
int cancel_sigs = 0; int cancel_sigs = 0;
/* cancel_sigs == 1 means that sigaction() failed without changing /* cancel_sigs == 1 means that sigaction() failed without changing
* the signal handlers. cancel_sigs == 2 means the signal handler * the signal handlers. cancel_sigs == 2 means the signal handler
* was changed, but the tcsetattr didn't succeed. * was changed, but the tcsetattr() didn't succeed.
* *
* I use this variable since it is important to put things back when * I use this variable since it is important to put things back when
* we finish, even if we get errors. */ * we finish, even if we get errors. */
@ -834,6 +828,9 @@ int open_pipe(const char *command)
/* Before we start reading the forked command's output, we set /* Before we start reading the forked command's output, we set
* things up so that ^C will cancel the new process. */ * things up so that ^C will cancel the new process. */
enable_signals();
if (sigaction(SIGINT, NULL, &newaction) == -1) { if (sigaction(SIGINT, NULL, &newaction) == -1) {
cancel_sigs = 1; cancel_sigs = 1;
nperror("sigaction"); nperror("sigaction");
@ -847,24 +844,6 @@ int open_pipe(const char *command)
/* Note that now oldaction is the previous SIGINT signal handler, /* Note that now oldaction is the previous SIGINT signal handler,
* to be restored later. */ * to be restored later. */
/* See if the platform supports disabling individual control
* characters. */
#ifdef _POSIX_VDISABLE
if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
cancel_sigs = 2;
nperror("tcgetattr");
}
if (cancel_sigs == 0) {
newterm = term;
/* Grab oldterm's VINTR key :-) */
newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
if (tcsetattr(0, TCSANOW, &newterm) == -1) {
cancel_sigs = 2;
nperror("tcsetattr");
}
}
#endif /* _POSIX_VDISABLE */
f = fdopen(fd[0], "rb"); f = fdopen(fd[0], "rb");
if (f == NULL) if (f == NULL)
nperror("fdopen"); nperror("fdopen");
@ -878,14 +857,11 @@ int open_pipe(const char *command)
if (wait(NULL) == -1) if (wait(NULL) == -1)
nperror("wait"); nperror("wait");
#ifdef _POSIX_VDISABLE
if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
nperror("tcsetattr");
#endif /* _POSIX_VDISABLE */
if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1) if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
nperror("sigaction"); nperror("sigaction");
disable_signals();
return 0; return 0;
} }
#endif /* !NANO_SMALL */ #endif /* !NANO_SMALL */
@ -2769,10 +2745,6 @@ int do_exit(void)
void signal_init(void) void signal_init(void)
{ {
#ifdef _POSIX_VDISABLE
struct termios term;
#endif
/* Trap SIGINT and SIGQUIT because we want them to do useful /* Trap SIGINT and SIGQUIT because we want them to do useful
* things. */ * things. */
memset(&act, 0, sizeof(struct sigaction)); memset(&act, 0, sizeof(struct sigaction));
@ -2792,31 +2764,10 @@ void signal_init(void)
allow_pending_sigwinch(FALSE); allow_pending_sigwinch(FALSE);
#endif #endif
#ifdef _POSIX_VDISABLE /* Trap normal suspend (^Z) so we can handle it ourselves. */
tcgetattr(0, &term);
if (!ISSET(PRESERVE)) {
/* Trap XOFF (^S) and XON (^Q), much to Chris' chagrin, because
* we want to block them. */
term.c_cc[VSTOP] = _POSIX_VDISABLE;
term.c_cc[VSTART] = _POSIX_VDISABLE;
}
#ifdef VDSUSP
/* Trap delayed suspend (^Y) so we can handle it ourselves. */
term.c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
#endif /* _POSIX_VDISABLE */
if (!ISSET(SUSPEND)) { if (!ISSET(SUSPEND)) {
/* Trap normal suspend (^Z) so we can handle it ourselves. If
* we can't trap the key, trap the signal instead. Insane! */
#ifdef _POSIX_VDISABLE
term.c_cc[VSUSP] = _POSIX_VDISABLE;
#else
act.sa_handler = SIG_IGN; act.sa_handler = SIG_IGN;
sigaction(SIGTSTP, &act, NULL); sigaction(SIGTSTP, &act, NULL);
#endif
} else { } else {
/* Block all other signals in the suspend and continue handlers. /* Block all other signals in the suspend and continue handlers.
* If we don't do this, other stuff interrupts them! */ * If we don't do this, other stuff interrupts them! */
@ -2828,54 +2779,44 @@ void signal_init(void)
act.sa_handler = do_cont; act.sa_handler = do_cont;
sigaction(SIGCONT, &act, NULL); sigaction(SIGCONT, &act, NULL);
} }
#ifdef _POSIX_VDISABLE
tcsetattr(0, TCSANOW, &term);
#endif
} }
/* Handler for SIGHUP and SIGTERM. */ /* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
RETSIGTYPE handle_hupterm(int signal) RETSIGTYPE handle_hupterm(int signal)
{ {
die(_("Received SIGHUP or SIGTERM\n")); die(_("Received SIGHUP or SIGTERM\n"));
} }
/* What do we do when we catch the suspend signal */ /* Handler for SIGTSTP (suspend). */
RETSIGTYPE do_suspend(int signal) RETSIGTYPE do_suspend(int signal)
{ {
endwin(); endwin();
printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano")); printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
fflush(stdout); fflush(stdout);
/* Restore the terminal settings for the disabled keys */ /* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &oldterm); tcsetattr(0, TCSANOW, &oldterm);
/* Trap SIGHUP and SIGTERM so we can properly deal with them while /* Trap SIGHUP and SIGTERM so we can properly deal with them while
suspended */ * suspended. */
act.sa_handler = handle_hupterm; act.sa_handler = handle_hupterm;
sigaction(SIGHUP, &act, NULL); sigaction(SIGHUP, &act, NULL);
sigaction(SIGTERM, &act, NULL); sigaction(SIGTERM, &act, NULL);
/* We used to re-enable the default SIG_DFL and raise SIGTSTP, but /* Do what mutt does: send ourselves a SIGSTOP. */
then we could be (and were) interrupted in the middle of the call.
So we do it the mutt way instead */
kill(0, SIGSTOP); kill(0, SIGSTOP);
} }
/* Restore the suspend handler when we come back into the prog */ /* Handler for SIGCONT (continue after suspend). */
RETSIGTYPE do_cont(int signal) RETSIGTYPE do_cont(int signal)
{ {
/* Now we just update the screen instead of having to reenable the
* SIGTSTP handler. */
doupdate();
#ifndef NANO_SMALL #ifndef NANO_SMALL
/* Perhaps the user resized the window while we slept. */ /* Perhaps the user resized the window while we slept. Handle it
* and update the screen in the process. */
handle_sigwinch(0); handle_sigwinch(0);
#else #else
/* Set up the signal handlers again, so that the special control /* Just update the screen. */
* keys all work the same as before. */ doupdate();
signal_init();
#endif #endif
} }
@ -2919,45 +2860,35 @@ void handle_sigwinch(int s)
memset(hblank, ' ', COLS); memset(hblank, ' ', COLS);
hblank[COLS] = '\0'; hblank[COLS] = '\0';
#ifdef HAVE_RESIZETERM #ifdef USE_SLANG
resizeterm(LINES, COLS); /* Slang curses emulation brain damage, part 1: If we just do what
#ifdef HAVE_WRESIZE * curses does here, it'll only work properly if the resize made the
if (wresize(topwin, 2, COLS) == ERR) * window smaller. Do what mutt does: Leave and immediately reenter
die(_("Cannot resize top win")); * Slang screen management mode. */
if (mvwin(topwin, 0, 0) == ERR) SLsmg_reset_smg();
die(_("Cannot move top win")); SLsmg_init_smg();
if (wresize(edit, editwinrows, COLS) == ERR) #else
die(_("Cannot resize edit win")); /* Do the equivalent of what Minimum Profit does: Leave and
if (mvwin(edit, 2, 0) == ERR) * immediately reenter curses mode. */
die(_("Cannot move edit win")); endwin();
if (wresize(bottomwin, 3 - no_help(), COLS) == ERR) refresh();
die(_("Cannot resize bottom win")); #endif
if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
die(_("Cannot move bottom win"));
#endif /* HAVE_WRESIZE */
#endif /* HAVE_RESIZETERM */
display_main_list(); /* Do the equivalent of what both mutt and Minimum Profit do:
* Reinitialize all the windows based on the new screen
* dimensions. */
window_init();
/* Redraw the contents of the windows that need it. */
blank_statusbar(); blank_statusbar();
display_main_list();
total_refresh(); total_refresh();
/* Turn cursor back on for sure. */ /* Turn cursor back on for sure. */
curs_set(1); curs_set(1);
/* Put the terminal in cbreak mode (read one character at a time and /* Restore the terminal to its previously saved state. */
* interpret the special control keys) if we can selectively disable resetty();
* the special control keys. */
#ifdef _POSIX_VDISABLE
cbreak();
#endif
/* Set up the signal handlers again, so that the special control
* keys all work the same as before. */
signal_init();
/* Turn the keypad on in the windows we'll be reading input from. */
keypad(edit, TRUE);
keypad(bottomwin, TRUE);
/* Jump back to the main loop. */ /* Jump back to the main loop. */
siglongjmp(jmpbuf, 1); siglongjmp(jmpbuf, 1);
@ -2993,7 +2924,8 @@ void do_toggle(const toggle *which)
break; break;
#endif #endif
case TOGGLE_NOHELP_KEY: case TOGGLE_NOHELP_KEY:
wclear(bottomwin); blank_statusbar();
blank_bottombars();
wrefresh(bottomwin); wrefresh(bottomwin);
window_init(); window_init();
edit_refresh(); edit_refresh();
@ -3022,6 +2954,46 @@ void do_toggle(const toggle *which)
} }
#endif /* !NANO_SMALL */ #endif /* !NANO_SMALL */
#if !defined(NANO_SMALL) || defined(USE_SLANG)
void disable_signals(void)
{
struct termios term;
tcgetattr(0, &term);
term.c_lflag &= ~ISIG;
tcsetattr(0, TCSANOW, &term);
}
#endif
#ifndef NANO_SMALL
void enable_signals(void)
{
struct termios term;
tcgetattr(0, &term);
term.c_lflag |= ISIG;
tcsetattr(0, TCSANOW, &term);
}
#endif
void disable_flow_control(void)
{
struct termios term;
tcgetattr(0, &term);
term.c_iflag &= ~(IXON|IXOFF);
tcsetattr(0, TCSANOW, &term);
}
void enable_flow_control(void)
{
struct termios term;
tcgetattr(0, &term);
term.c_iflag |= (IXON|IXOFF);
tcsetattr(0, TCSANOW, &term);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int optchr; int optchr;
@ -3036,9 +3008,6 @@ int main(int argc, char *argv[])
#ifndef NANO_SMALL #ifndef NANO_SMALL
const toggle *t; const toggle *t;
#endif #endif
#ifdef _POSIX_VDISABLE
struct termios term;
#endif
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
const struct option long_options[] = { const struct option long_options[] = {
{"help", 0, 0, 'h'}, {"help", 0, 0, 'h'},
@ -3428,36 +3397,35 @@ int main(int argc, char *argv[])
filename = mallocstrcpy(filename, argv[optind]); filename = mallocstrcpy(filename, argv[optind]);
} }
/* Termios initialization stuff: Back up the old settings so that /* Back up the old terminal settings so that they can be restored. */
* they can be restored, disable SIGINT on ^C and SIGQUIT on ^\,
* since we need them for Cancel and Replace, and disable
* implementation-defined input processing. */
tcgetattr(0, &oldterm); tcgetattr(0, &oldterm);
#ifdef _POSIX_VDISABLE
term = oldterm;
term.c_cc[VINTR] = _POSIX_VDISABLE;
term.c_cc[VQUIT] = _POSIX_VDISABLE;
term.c_lflag &= ~IEXTEN;
tcsetattr(0, TCSANOW, &term);
#endif
/* Curses initialization stuff: Start curses, save the state of the /* Curses initialization stuff: Start curses, save the state of the
* the terminal mode, disable translation of carriage return (^M) * terminal mode, put the terminal in raw mode (read one character at
* into newline (^J) so we can catch the Enter key and use ^J for * a time and don't interpret the special control keys), disable
* Justify, put the terminal in cbreak mode (read one character at a * translation of carriage return (^M) into newline (^J) so that we
* time and interpret the special control keys) if we can selectively * can tell the difference between the Enter key and ^J, and disable
* disable the special control keys or raw mode (read one character * echoing of characters as they're typed. Finally, if we're in
* at a time and don't interpret the special control keys) if we * preserve mode, turn the flow control characters back on. */
* can't, and turn off echoing of characters as they're typed. */
initscr(); initscr();
savetty();
nonl();
#ifdef _POSIX_VDISABLE
cbreak();
#else
raw(); raw();
#ifdef USE_SLANG
/* Slang curses emulation brain damage, part 2: Raw mode acts just
* like cbreak mode here and doesn't disable interpretation of the
* special control keys. Work around this by manually disabling
* interpretation of the special control keys. */
disable_signals();
#endif #endif
nonl();
noecho(); noecho();
if (ISSET(PRESERVE))
enable_flow_control();
#ifndef NANO_SMALL
/* Save the terminal's current state, so that we can restore it
* after a resize. */
savetty();
#endif
/* Set up the global variables and the shortcuts. */ /* Set up the global variables and the shortcuts. */
global_init(0); global_init(0);
@ -3511,8 +3479,10 @@ int main(int argc, char *argv[])
if (startline > 0) if (startline > 0)
do_gotoline(startline, 0); do_gotoline(startline, 0);
/* Return here after a sigwinch */ #ifndef NANO_SMALL
/* Return here after a SIGWINCH. */
sigsetjmp(jmpbuf, 1); sigsetjmp(jmpbuf, 1);
#endif
/* SHUT UP GCC! */ /* SHUT UP GCC! */
startline = 0; startline = 0;
@ -3598,13 +3568,12 @@ int main(int argc, char *argv[])
if (!keyhandled) if (!keyhandled)
UNSET(KEEP_CUTBUFFER); UNSET(KEEP_CUTBUFFER);
#ifdef _POSIX_VDISABLE
/* Don't even think about changing this string */ /* Don't even think about changing this string */
if (kbinput == NANO_CONTROL_Q) if (kbinput == NANO_CONTROL_Q)
statusbar(_("XON ignored, mumble mumble.")); statusbar(_("XON ignored, mumble mumble."));
if (kbinput == NANO_CONTROL_S) if (kbinput == NANO_CONTROL_S)
statusbar(_("XOFF ignored, mumble mumble.")); statusbar(_("XOFF ignored, mumble mumble."));
#endif
/* If we're in raw mode or using Alt-Alt-x, we have to catch /* If we're in raw mode or using Alt-Alt-x, we have to catch
Control-S and Control-Q */ Control-S and Control-Q */
if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S) if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)

View File

@ -54,9 +54,10 @@
#endif #endif
#ifdef USE_SLANG #ifdef USE_SLANG
/* Slang support enabled. Work around Slang's not defining KEY_DC or /* Slang support enabled. */
* KEY_IC. */
#include <slcurses.h> #include <slcurses.h>
/* Slang curses emulation brain damage, part 3: Slang doesn't define the
* curses equivalents of the Insert or Delete keys. */
#define KEY_DC SL_KEY_DELETE #define KEY_DC SL_KEY_DELETE
#define KEY_IC SL_KEY_IC #define KEY_IC SL_KEY_IC
#elif defined(HAVE_NCURSES_H) #elif defined(HAVE_NCURSES_H)

View File

@ -54,7 +54,7 @@ extern char *quotestr;
extern char *backup_dir; extern char *backup_dir;
#endif #endif
extern WINDOW *edit, *topwin, *bottomwin; extern WINDOW *topwin, *edit, *bottomwin;
extern char *filename; extern char *filename;
extern struct stat originalfilestat; extern struct stat originalfilestat;
extern char *answer; extern char *answer;
@ -151,7 +151,8 @@ int do_uncut_text(void);
/* Public functions in files.c */ /* Public functions in files.c */
void load_file(int update); void load_file(int update);
void new_file(void); void new_file(void);
filestruct *read_line(char *buf, filestruct *prev, int *line1ins, int len); filestruct *read_line(char *buf, filestruct *prev, int *line1ins, size_t
len);
int read_file(FILE *f, const char *filename, int quiet); int read_file(FILE *f, const char *filename, int quiet);
int open_file(const char *filename, int insert, int quiet); int open_file(const char *filename, int insert, int quiet);
char *get_next_filename(const char *name); char *get_next_filename(const char *name);
@ -202,7 +203,7 @@ char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list)
const char *tail(const char *foo); const char *tail(const char *foo);
#ifndef DISABLE_BROWSER #ifndef DISABLE_BROWSER
int diralphasort(const void *va, const void *vb); int diralphasort(const void *va, const void *vb);
void free_charptrarray(char **array, int len); void free_charptrarray(char **array, size_t len);
void striponedir(char *foo); void striponedir(char *foo);
int readable_dir(const char *path); int readable_dir(const char *path);
char **browser_init(const char *path, int *longest, int *numents); char **browser_init(const char *path, int *longest, int *numents);
@ -268,7 +269,6 @@ void print1opt(const char *shortflag, const char *longflag,
const char *desc); const char *desc);
void usage(void); void usage(void);
void version(void); void version(void);
void do_early_abort(void);
int no_help(void); int no_help(void);
int nano_disabled_msg(void); int nano_disabled_msg(void);
#ifndef NANO_SMALL #ifndef NANO_SMALL
@ -342,6 +342,14 @@ void allow_pending_sigwinch(int allow);
#ifndef NANO_SMALL #ifndef NANO_SMALL
void do_toggle(const toggle *which); void do_toggle(const toggle *which);
#endif #endif
#if !defined(NANO_SMALL) || defined(USE_SLANG)
void disable_signals(void);
#endif
#ifndef NANO_SMALL
void enable_signals(void);
#endif
void disable_flow_control(void);
void enable_flow_control(void);
/* Public functions in rcfile.c */ /* Public functions in rcfile.c */
#ifdef ENABLE_NANORC #ifdef ENABLE_NANORC
@ -469,13 +477,13 @@ size_t xplustabs(void);
size_t actual_x(const char *str, size_t xplus); size_t actual_x(const char *str, size_t xplus);
size_t strnlenpt(const char *buf, size_t size); size_t strnlenpt(const char *buf, size_t size);
size_t strlenpt(const char *buf); size_t strlenpt(const char *buf);
void blank_bottombars(void); void blank_titlebar(void);
void blank_bottomwin(void);
void blank_edit(void); void blank_edit(void);
void blank_statusbar(void); void blank_statusbar(void);
void blank_statusbar_refresh(void); void blank_statusbar_refresh(void);
void check_statblank(void); void check_statblank(void);
char *display_string(const char *buf, size_t start_col, int len); void blank_bottombars(void);
char *display_string(const char *buf, size_t start_col, size_t len);
void nanoget_repaint(const char *buf, const char *inputbuf, size_t x); void nanoget_repaint(const char *buf, const char *inputbuf, size_t x);
int nanogetstr(int allowtabs, const char *buf, const char *def, int nanogetstr(int allowtabs, const char *buf, const char *def,
#ifndef NANO_SMALL #ifndef NANO_SMALL
@ -486,8 +494,9 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
, int *list , int *list
#endif #endif
); );
void set_modified(void);
void titlebar(const char *path); void titlebar(const char *path);
void set_modified(void);
void statusbar(const char *msg, ...);
void bottombars(const shortcut *s); void bottombars(const shortcut *s);
void onekey(const char *keystroke, const char *desc, int len); void onekey(const char *keystroke, const char *desc, int len);
#ifndef NDEBUG #ifndef NDEBUG
@ -511,7 +520,6 @@ int statusq(int allowtabs, const shortcut *s, const char *def,
int do_yesno(int all, const char *msg); int do_yesno(int all, const char *msg);
int total_refresh(void); int total_refresh(void);
void display_main_list(void); void display_main_list(void);
void statusbar(const char *msg, ...);
int do_cursorpos(int constant); int do_cursorpos(int constant);
int do_cursorpos_void(void); int do_cursorpos_void(void);
int line_len(const char *ptr); int line_len(const char *ptr);

View File

@ -129,14 +129,11 @@ int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len, int
allow_pending_sigwinch(TRUE); allow_pending_sigwinch(TRUE);
#endif #endif
/* Switch to raw mode if necessary so that we can type ^C, ^Q, ^S, /* Turn off flow control characters if necessary so that we can type
* ^Z, and ^\ (and ^Y on systems supporting delayed suspend) without * them in verbatim, and turn the keypad off so that we don't get
* getting interrupts, and turn the keypad off so that we don't get * extended keypad values outside the ASCII range. */
* extended keypad values, all of which are outside the ASCII if (ISSET(PRESERVE))
* range. */ disable_flow_control();
#ifdef _POSIX_VDISABLE
raw();
#endif
keypad(win, FALSE); keypad(win, FALSE);
kbinput = wgetch(win); kbinput = wgetch(win);
@ -165,11 +162,10 @@ int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len, int
nodelay(win, FALSE); nodelay(win, FALSE);
} }
/* Switch back to cbreak mode if necessary and turn the keypad back /* Turn flow control characters back on if necessary and turn the
* on now that we're done. */ * keypad back on now that we're done. */
#ifdef _POSIX_VDISABLE if (ISSET(PRESERVE))
cbreak(); enable_flow_control();
#endif
keypad(win, TRUE); keypad(win, TRUE);
#ifndef NANO_SMALL #ifndef NANO_SMALL
@ -1096,26 +1092,14 @@ size_t strlenpt(const char *buf)
return strnlenpt(buf, (size_t)-1); return strnlenpt(buf, (size_t)-1);
} }
void blank_bottombars(void) void blank_titlebar(void)
{ {
if (!ISSET(NO_HELP)) { mvwaddstr(topwin, 0, 0, hblank);
mvwaddstr(bottomwin, 1, 0, hblank);
mvwaddstr(bottomwin, 2, 0, hblank);
}
}
void blank_bottomwin(void)
{
if (ISSET(NO_HELP))
return;
mvwaddstr(bottomwin, 1, 0, hblank);
mvwaddstr(bottomwin, 2, 0, hblank);
} }
void blank_edit(void) void blank_edit(void)
{ {
int i; size_t i;
for (i = 0; i < editwinrows; i++) for (i = 0; i < editwinrows; i++)
mvwaddstr(edit, i, 0, hblank); mvwaddstr(edit, i, 0, hblank);
} }
@ -1141,12 +1125,20 @@ void check_statblank(void)
} }
} }
void blank_bottombars(void)
{
if (!ISSET(NO_HELP)) {
mvwaddstr(bottomwin, 1, 0, hblank);
mvwaddstr(bottomwin, 2, 0, hblank);
}
}
/* Convert buf into a string that can be displayed on screen. The /* Convert buf into a string that can be displayed on screen. The
* caller wants to display buf starting with column start_col, and * caller wants to display buf starting with column start_col, and
* extending for at most len columns. start_col is zero-based. len is * extending for at most len columns. start_col is zero-based. len is
* one-based, so len == 0 means you get "" returned. The returned * one-based, so len == 0 means you get "" returned. The returned
* string is dynamically allocated, and should be freed. */ * string is dynamically allocated, and should be freed. */
char *display_string(const char *buf, size_t start_col, int len) char *display_string(const char *buf, size_t start_col, size_t len)
{ {
size_t start_index; size_t start_index;
/* Index in buf of first character shown in return value. */ /* Index in buf of first character shown in return value. */
@ -1539,16 +1531,6 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
return 0; return 0;
} }
/* If modified is not already set, set it and update titlebar. */
void set_modified(void)
{
if (!ISSET(MODIFIED)) {
SET(MODIFIED);
titlebar(NULL);
wrefresh(topwin);
}
}
void titlebar(const char *path) void titlebar(const char *path)
{ {
int namelen, space; int namelen, space;
@ -1559,7 +1541,7 @@ void titlebar(const char *path)
wattron(topwin, A_REVERSE); wattron(topwin, A_REVERSE);
mvwaddstr(topwin, 0, 0, hblank); blank_titlebar();
mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3); mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
space = COLS - sizeof(VERMSG) - 23; space = COLS - sizeof(VERMSG) - 23;
@ -1597,6 +1579,64 @@ void titlebar(const char *path)
reset_cursor(); reset_cursor();
} }
/* If modified is not already set, set it and update titlebar. */
void set_modified(void)
{
if (!ISSET(MODIFIED)) {
SET(MODIFIED);
titlebar(NULL);
wrefresh(topwin);
}
}
void statusbar(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
/* Curses mode is turned off. If we use wmove() now, it will muck
* up the terminal settings. So we just use vfprintf(). */
if (curses_ended) {
vfprintf(stderr, msg, ap);
va_end(ap);
return;
}
/* Blank out the line. */
blank_statusbar();
if (COLS >= 4) {
char *bar;
char *foo;
size_t start_x = 0, foo_len;
bar = charalloc(COLS - 3);
vsnprintf(bar, COLS - 3, msg, ap);
va_end(ap);
foo = display_string(bar, 0, COLS - 4);
free(bar);
foo_len = strlen(foo);
start_x = (COLS - foo_len - 4) / 2;
wmove(bottomwin, 0, start_x);
wattron(bottomwin, A_REVERSE);
waddstr(bottomwin, "[ ");
waddstr(bottomwin, foo);
free(foo);
waddstr(bottomwin, " ]");
wattroff(bottomwin, A_REVERSE);
wnoutrefresh(bottomwin);
reset_cursor();
wrefresh(edit);
/* Leave the cursor at its position in the edit window, not
* in the statusbar. */
}
SET(DISABLE_CURPOS);
statblank = 26;
}
void bottombars(const shortcut *s) void bottombars(const shortcut *s)
{ {
int i, j, numcols; int i, j, numcols;
@ -1620,7 +1660,7 @@ void bottombars(const shortcut *s)
/* There will be this many columns of shortcuts */ /* There will be this many columns of shortcuts */
numcols = (slen + (slen % 2)) / 2; numcols = (slen + (slen % 2)) / 2;
blank_bottomwin(); blank_bottombars();
for (i = 0; i < numcols; i++) { for (i = 0; i < numcols; i++) {
for (j = 0; j <= 1; j++) { for (j = 0; j <= 1; j++) {
@ -2370,15 +2410,15 @@ int do_yesno(int all, const char *msg)
int total_refresh(void) int total_refresh(void)
{ {
clearok(edit, TRUE);
clearok(topwin, TRUE); clearok(topwin, TRUE);
clearok(edit, TRUE);
clearok(bottomwin, TRUE); clearok(bottomwin, TRUE);
wnoutrefresh(edit);
wnoutrefresh(topwin); wnoutrefresh(topwin);
wnoutrefresh(edit);
wnoutrefresh(bottomwin); wnoutrefresh(bottomwin);
doupdate(); doupdate();
clearok(edit, FALSE);
clearok(topwin, FALSE); clearok(topwin, FALSE);
clearok(edit, FALSE);
clearok(bottomwin, FALSE); clearok(bottomwin, FALSE);
edit_refresh(); edit_refresh();
titlebar(NULL); titlebar(NULL);
@ -2390,62 +2430,13 @@ void display_main_list(void)
bottombars(main_list); bottombars(main_list);
} }
void statusbar(const char *msg, ...) /* If constant is FALSE, the user typed ^C so we unconditionally display
{
va_list ap;
va_start(ap, msg);
/* Curses mode is turned off. If we use wmove() now, it will muck
* up the terminal settings. So we just use vfprintf(). */
if (curses_ended) {
vfprintf(stderr, msg, ap);
va_end(ap);
return;
}
/* Blank out the line. */
blank_statusbar();
if (COLS >= 4) {
char *bar;
char *foo;
int start_x = 0;
size_t foo_len;
bar = charalloc(COLS - 3);
vsnprintf(bar, COLS - 3, msg, ap);
va_end(ap);
foo = display_string(bar, 0, COLS - 4);
free(bar);
foo_len = strlen(foo);
start_x = (COLS - foo_len - 4) / 2;
wmove(bottomwin, 0, start_x);
wattron(bottomwin, A_REVERSE);
waddstr(bottomwin, "[ ");
waddstr(bottomwin, foo);
free(foo);
waddstr(bottomwin, " ]");
wattroff(bottomwin, A_REVERSE);
wnoutrefresh(bottomwin);
reset_cursor();
wrefresh(edit);
/* Leave the cursor at its position in the edit window, not
* in the statusbar. */
}
SET(DISABLE_CURPOS);
statblank = 26;
}
/* If constant is false, the user typed ^C so we unconditionally display
* the cursor position. Otherwise, we display it only if the character * the cursor position. Otherwise, we display it only if the character
* position changed, and DISABLE_CURPOS is not set. * position changed, and DISABLE_CURPOS is not set.
* *
* If constant and DISABLE_CURPOS is set, we unset it and update old_i and * If constant is TRUE and DISABLE_CURPOS is set, we unset it and update
* old_totsize. That way, we leave the current statusbar alone, but next * old_i and old_totsize. That way, we leave the current statusbar
* time we will display. */ * alone, but next time we will display. */
int do_cursorpos(int constant) int do_cursorpos(int constant)
{ {
const filestruct *fileptr; const filestruct *fileptr;
@ -2533,7 +2524,7 @@ int line_len(const char *ptr)
int do_help(void) int do_help(void)
{ {
int i, page = 0, kbinput = ERR, meta_key, no_more = 0; int i, page = 0, kbinput = ERR, meta_key, no_more = 0;
int no_help_flag = 0; int no_help_flag = FALSE;
const shortcut *oldshortcut; const shortcut *oldshortcut;
blank_edit(); blank_edit();
@ -2553,7 +2544,7 @@ int do_help(void)
/* Well, if we're going to do this, we should at least do it the /* Well, if we're going to do this, we should at least do it the
* right way. */ * right way. */
no_help_flag = 1; no_help_flag = TRUE;
UNSET(NO_HELP); UNSET(NO_HELP);
window_init(); window_init();
bottombars(help_list); bottombars(help_list);
@ -2701,17 +2692,13 @@ void dump_buffer_reverse(void)
/* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */ /* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */
void do_credits(void) void do_credits(void)
{ {
int i, j = 0, k, place = 0, start_x; int crpos = 0, xlpos = 0;
const char *credits[CREDIT_LEN] = {
const char *what; NULL, /* "The nano text editor" */
const char *xlcredits[XLCREDIT_LEN]; NULL, /* "version" */
const char *credits[CREDIT_LEN] = {
"0", /* "The nano text editor" */
"1", /* "version" */
VERSION, VERSION,
"", "",
"2", /* "Brought to you by:" */ NULL, /* "Brought to you by:" */
"Chris Allegretta", "Chris Allegretta",
"Jordi Mallach", "Jordi Mallach",
"Adam Rogoyski", "Adam Rogoyski",
@ -2734,80 +2721,82 @@ void do_credits(void)
"Ryan Krebs", "Ryan Krebs",
"Albert Chin", "Albert Chin",
"", "",
"3", /* "Special thanks to:" */ NULL, /* "Special thanks to:" */
"Plattsburgh State University", "Plattsburgh State University",
"Benet Laboratories", "Benet Laboratories",
"Amy Allegretta", "Amy Allegretta",
"Linda Young", "Linda Young",
"Jeremy Robichaud", "Jeremy Robichaud",
"Richard Kolb II", "Richard Kolb II",
"4", /* "The Free Software Foundation" */ NULL, /* "The Free Software Foundation" */
"Linus Torvalds", "Linus Torvalds",
"5", /* "For ncurses:" */ NULL, /* "For ncurses:" */
"Thomas Dickey", "Thomas Dickey",
"Pavel Curtis", "Pavel Curtis",
"Zeyd Ben-Halim", "Zeyd Ben-Halim",
"Eric S. Raymond", "Eric S. Raymond",
"6", /* "and anyone else we forgot..." */ NULL, /* "and anyone else we forgot..." */
"7", /* "Thank you for using nano!\n" */ NULL, /* "Thank you for using nano!" */
"", "", "", "", "",
"",
"",
"",
"(c) 1999-2004 Chris Allegretta", "(c) 1999-2004 Chris Allegretta",
"", "", "", "", "",
"",
"",
"",
"http://www.nano-editor.org/" "http://www.nano-editor.org/"
}; };
xlcredits[0] = _("The nano text editor"); const char *xlcredits[XLCREDIT_LEN] = {
xlcredits[1] = _("version "); _("The nano text editor"),
xlcredits[2] = _("Brought to you by:"); _("version"),
xlcredits[3] = _("Special thanks to:"); _("Brought to you by:"),
xlcredits[4] = _("The Free Software Foundation"); _("Special thanks to:"),
xlcredits[5] = _("For ncurses:"); _("The Free Software Foundation"),
xlcredits[6] = _("and anyone else we forgot..."); _("For ncurses:"),
xlcredits[7] = _("Thank you for using nano!\n"); _("and anyone else we forgot..."),
_("Thank you for using nano!")
};
curs_set(0); curs_set(0);
nodelay(edit, TRUE); nodelay(edit, TRUE);
blank_bottombars(); scrollok(edit, TRUE);
mvwaddstr(topwin, 0, 0, hblank); blank_titlebar();
blank_edit(); blank_edit();
blank_statusbar();
blank_bottombars();
wrefresh(topwin);
wrefresh(edit); wrefresh(edit);
wrefresh(bottomwin); wrefresh(bottomwin);
wrefresh(topwin);
while (wgetch(edit) == ERR) { for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) {
for (k = 0; k <= 1; k++) { if (wgetch(edit) != ERR)
blank_edit();
for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
i--) {
mvwaddstr(edit, i * 2 - k, 0, hblank);
if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
what = credits[place - (editwinrows / 2 - 1 - i)];
/* God I've missed hacking. If what is exactly
1 char long, it's a sentinel for a translated
string, so use that instead. This means no
thanking people with 1 character long names ;-) */
if (strlen(what) == 1)
what = xlcredits[atoi(what)];
} else
what = "";
start_x = COLS / 2 - strlen(what) / 2 - 1;
mvwaddstr(edit, i * 2 - k, start_x, what);
}
napms(700);
wrefresh(edit);
}
if (j < editwinrows / 2 - 1)
j++;
place++;
if (place >= CREDIT_LEN + editwinrows / 2)
break; break;
if (crpos < CREDIT_LEN) {
const char *what = credits[crpos];
size_t start_x;
if (what == NULL) {
assert(0 <= xlpos && xlpos < XLCREDIT_LEN);
what = xlcredits[xlpos];
xlpos++;
}
start_x = COLS / 2 - strlen(what) / 2 - 1;
mvwaddstr(edit, editwinrows - 1 - editwinrows % 2, start_x, what);
}
napms(700);
scroll(edit);
wrefresh(edit);
if (wgetch(edit) != ERR)
break;
napms(700);
scroll(edit);
wrefresh(edit);
} }
scrollok(edit, FALSE);
nodelay(edit, FALSE); nodelay(edit, FALSE);
curs_set(1); curs_set(1);
display_main_list(); display_main_list();