"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.2/src/signal.c" (9 Dec 2022, 14547 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "signal.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.6.1_vs_2.6.2.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : signal.c
    4  *  Author    : I.Lea
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2022-01-11
    7  *  Notes     : signal handlers for different modes and window resizing
    8  *
    9  * Copyright (c) 1991-2023 Iain Lea <iain@bricbrac.de>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  *
   16  * 1. Redistributions of source code must retain the above copyright notice,
   17  *    this list of conditions and the following disclaimer.
   18  *
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  *
   23  * 3. Neither the name of the copyright holder nor the names of its
   24  *    contributors may be used to endorse or promote products derived from
   25  *    this software without specific prior written permission.
   26  *
   27  * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 
   41 #ifndef TIN_H
   42 #   include "tin.h"
   43 #endif /* !TIN_H */
   44 #ifndef TCURSES_H
   45 #   include "tcurses.h"
   46 #endif /* !TCURSES_H */
   47 #ifndef included_trace_h
   48 #   include "trace.h"
   49 #endif /* !included_trace_h */
   50 #ifndef VERSION_H
   51 #   include "version.h"
   52 #endif /* !VERSION_H */
   53 
   54 /*
   55  * Needed for resizing under an xterm
   56  */
   57 #ifdef HAVE_TERMIOS_H
   58 #   include <termios.h>
   59 #else
   60 #   ifdef HAVE_TERMIO_H
   61 #       include <termio.h>
   62 #   endif /* HAVE_TERMIO_H */
   63 #endif /* HAVE_TERMIOS_H */
   64 
   65 #ifdef NEED_PTEM_H
   66 #   ifdef HAVE_SYS_STREAM_H
   67 #       include <sys/stream.h>
   68 #   endif /* HAVE_SYS_STREAM_H */
   69 #   include <sys/ptem.h>
   70 #endif /* NEED_PTEM_H */
   71 
   72 #if defined(SIGWINCH) && !defined(DONT_HAVE_SIGWINCH)
   73 #   if !defined(TIOCGWINSZ) && !defined(TIOCGSIZE)
   74 #       ifdef HAVE_SYS_STREAM_H
   75 #           include <sys/stream.h>
   76 #       endif /* HAVE_SYS_STREAM_H */
   77 #       ifdef HAVE_SYS_PTY_H
   78 #           if !defined(_h_BSDTYPES) && defined(HAVE_SYS_BSDTYPES_H)
   79 #               include <sys/bsdtypes.h>
   80 #           endif /* !_h_BSDTYPES && HAVE_SYS_BSDTYPES_H */
   81 #           include <sys/pty.h>
   82 #       endif /* HAVE_SYS_PTY_H */
   83 #   endif /* !TIOCGWINSZ && !TIOCGSIZE */
   84 #endif /* SIGWINCH && !DONT_HAVE_SIGWINCH */
   85 
   86 #ifdef MINIX
   87 #   undef SIGTSTP
   88 #endif /* MINIX */
   89 
   90 /*
   91  * local prototypes
   92  */
   93 static const char *signal_name(int code);
   94 #ifdef SIGTSTP
   95     static void handle_suspend(void);
   96 #endif /* SIGTSTP */
   97 static void _CDECL signal_handler(SIG_ARGS);
   98 
   99 
  100 #ifdef SIGTSTP
  101     static t_bool do_sigtstp = FALSE;
  102 #endif /* SIGTSTP */
  103 #if defined(SIGWINCH) || defined(SIGTSTP)
  104     static t_bool redraw_after_suspend;
  105 #endif /* SIGWINCH || SIGTSTP */
  106 
  107 int signal_context = cMain;
  108 int input_context = cNone;
  109 int need_resize = cNo;
  110 /*
  111  * # lines of non-static data available for display
  112  */
  113 int NOTESLINES;
  114 
  115 
  116 #ifndef __LCLINT__ /* lclint doesn't like it */
  117 static const struct {
  118     int code;
  119     const char *name;
  120 } signal_list[] = {
  121 #   ifdef SIGINT
  122     { SIGINT,   "SIGINT" }, /* ctrl-C */
  123 #   endif /* SIGINT */
  124 #   ifdef SIGQUIT
  125     { SIGQUIT,  "SIGQUIT" },    /* ctrl-\ */
  126 #   endif /* SIGQUIT */
  127 #   ifdef SIGILL
  128     { SIGILL,   "SIGILL" }, /* illegal instruction */
  129 #   endif /* SIGILL */
  130 #   ifdef SIGFPE
  131     { SIGFPE,   "SIGFPE" }, /* floating point exception */
  132 #   endif /* SIGFPE */
  133 #   ifdef SIGBUS
  134     { SIGBUS,   "SIGBUS" }, /* bus error */
  135 #   endif /* SIGBUS */
  136 #   ifdef SIGSEGV
  137     { SIGSEGV,  "SIGSEGV" },    /* segmentation violation */
  138 #   endif /* SIGSEGV */
  139 #   ifdef SIGPIPE
  140     { SIGPIPE,  "SIGPIPE" },    /* broken pipe */
  141 #   endif /* SIGPIPE */
  142 #   ifdef SIGALRM
  143     { SIGALRM,  "SIGALRM" },    /* real-time timer expired */
  144 #   endif /* SIGALRM */
  145 #   ifdef SIGCHLD
  146     { SIGCHLD,  "SIGCHLD" },    /* death of a child process */
  147 #   endif /* SIGCHLD */
  148 #   ifdef SIGPWR
  149     { SIGPWR,   "SIGPWR" }, /* powerfail */
  150 #   endif /* SIGPWR */
  151 #   ifdef SIGTSTP
  152     { SIGTSTP,  "SIGTSTP" },    /* terminal-stop */
  153 #   endif /* SIGTSTP */
  154 #   ifdef SIGHUP
  155     { SIGHUP,   "SIGHUP" }, /* hang up */
  156 #   endif /* SIGHUP */
  157 #   ifdef SIGUSR1
  158     { SIGUSR1,  "SIGUSR1" },    /* User-defined signal 1 */
  159 #   endif /* SIGUSR1 */
  160 #   ifdef SIGUSR2
  161     { SIGUSR2,  "SIGUSR2" },    /* User-defined signal 2 */
  162 #   endif /* SIGUSR2 */
  163 #   ifdef SIGTERM
  164     { SIGTERM,  "SIGTERM" },    /* termination */
  165 #   endif /* SIGTERM */
  166 #   if defined(SIGWINCH) && !(defined(USE_CURSES) && defined(KEY_RESIZE))
  167     { SIGWINCH, "SIGWINCH" },   /* window-size change */
  168 #   endif /* SIGWINCH && !(USE_CURSES && KEY_RESIZE) */
  169 };
  170 #endif /* !__LCLINT__ */
  171 
  172 
  173 #ifdef HAVE_NESTED_PARAMS
  174     RETSIGTYPE (*sigdisp(int signum, RETSIGTYPE (_CDECL *func)(SIG_ARGS)))(SIG_ARGS)
  175 #else
  176     RETSIGTYPE (*sigdisp(signum, func))(SIG_ARGS)
  177     int signum;
  178     RETSIGTYPE (_CDECL *func)(SIG_ARGS);
  179 #endif /* HAVE_NESTED_PARAMS */
  180 {
  181 #ifdef HAVE_POSIX_JC
  182 #   define RESTORE_HANDLER(x, y)
  183     struct sigaction sa, osa;
  184 
  185     sa.sa_handler = func;
  186     sigemptyset(&sa.sa_mask);
  187     sa.sa_flags = 0;
  188 #   ifdef SA_RESTART
  189         sa.sa_flags |= SA_RESTART;
  190 #   endif /* SA_RESTART */
  191     if (sigaction(signum, &sa, &osa) < 0)
  192         return SIG_ERR;
  193     return (osa.sa_handler);
  194 #else
  195 #   define RESTORE_HANDLER(x, y)    signal(x, y)
  196     return (signal(signum, func));
  197 #endif /* HAVE_POSIX_JC */
  198 }
  199 
  200 
  201 /*
  202  * Block/unblock SIGWINCH/SIGTSTP restarting syscalls
  203  */
  204 void
  205 allow_resize(
  206     t_bool allow)
  207 {
  208 #ifdef HAVE_POSIX_JC
  209     struct sigaction sa, osa;
  210 
  211     sa.sa_handler = signal_handler;
  212     sigemptyset(&sa.sa_mask);
  213     sa.sa_flags = 0;
  214 #   ifdef SA_RESTART
  215     if (!allow)
  216         sa.sa_flags |= SA_RESTART;
  217 #   endif /* SA_RESTART */
  218 #   if defined(SIGWINCH) && !(defined(USE_CURSES) && defined(KEY_RESIZE))
  219     sigaction(SIGWINCH, &sa, &osa);
  220 #   endif /* SIGWINCH && !(USE_CURSES && KEY_RESIZE) */
  221 #   ifdef SIGTSTP
  222     sigaction(SIGTSTP, &sa, &osa);
  223 #   endif /* SIGTSTP */
  224 #endif /* HAVE_POSIX_JC */
  225 }
  226 
  227 
  228 static const char *
  229 signal_name(
  230     int code)
  231 {
  232     size_t n;
  233     const char *name = "unknown";
  234 
  235     for (n = 0; n < ARRAY_SIZE(signal_list); n++) {
  236         if (signal_list[n].code == code) {
  237             name = signal_list[n].name;
  238             break;
  239         }
  240     }
  241     return name;
  242 }
  243 
  244 
  245 /*
  246  * Rescale the display buffer and redraw the contents according to
  247  * the current context
  248  * This should NOT be called from an interrupt context
  249  */
  250 void
  251 handle_resize(
  252     t_bool repaint)
  253 {
  254 #if defined(SIGWINCH) || defined(SIGTSTP)
  255 #   ifdef SIGWINCH
  256     repaint |= set_win_size(&cLINES, &cCOLS);
  257 #   endif /* SIGWINCH */
  258 
  259     if (cLINES < MIN_LINES_ON_TERMINAL || cCOLS < MIN_COLUMNS_ON_TERMINAL) {
  260         ring_bell();
  261         tin_done(EXIT_FAILURE, _(txt_screen_too_small_exiting), tin_progname);
  262     }
  263 
  264     TRACE(("handle_resize(%d:%d)", signal_context, repaint));
  265 
  266     if (!repaint)
  267         return;
  268 
  269 #   ifdef USE_CURSES
  270 #       ifdef HAVE_RESIZETERM
  271     resizeterm(cLINES + 1, cCOLS);
  272     my_retouch();                   /* seems necessary if win size unchanged */
  273 #       else
  274     my_retouch();
  275 #       endif /* HAVE_RESIZETERM */
  276 #   endif /* USE_CURSES */
  277 
  278     switch (signal_context) {
  279         case cArt:
  280             ClearScreen();
  281             show_art_msg(CURR_GROUP.name);
  282             break;
  283 
  284         case cAttrib:
  285         case cConfig:
  286             refresh_config_page(SIGNAL_HANDLER);
  287             break;
  288 
  289         case cFilter:
  290             refresh_filter_menu();
  291             break;
  292 
  293         case cInfopager:
  294             display_info_page(0);
  295             break;
  296 
  297         case cAttachment:
  298         case cGroup:
  299         case cPOSTED:
  300         case cScope:
  301         case cSelect:
  302         case cThread:
  303         case cURL:
  304             ClearScreen();
  305             currmenu->redraw();
  306             break;
  307 
  308         case cPage:
  309             resize_article(TRUE, &pgart);
  310             draw_page(curr_group->name, 0);
  311             break;
  312 
  313         case cPost:
  314         case cPostCancel:
  315             refresh_post_screen(signal_context);
  316             break;
  317 
  318         case cPostFup:
  319             resize_article(TRUE, &pgart);
  320             draw_page(curr_group->name, 0);
  321             /*
  322              * Reset signal_context because draw_page()
  323              * sets signal_context to cPage.
  324              */
  325             signal_context = cPostFup;
  326             refresh_post_screen(signal_context);
  327             break;
  328 
  329         case cReconnect:
  330             ClearScreen();
  331             show_title(tin_progname);
  332             break;
  333 
  334         case cMain:
  335             break;
  336     }
  337     switch (input_context) {
  338         case cGetline:
  339             gl_redraw();
  340             break;
  341 
  342         case cPromptCONT:
  343             if (redraw_after_suspend)
  344                 info_message(_(txt_return_key));
  345             break;
  346 
  347         case cPromptSLK:
  348             prompt_slk_redraw();
  349             break;
  350 
  351         case cPromptYN:
  352             prompt_yn_redraw();
  353             break;
  354 
  355         default:
  356             break;
  357     }
  358     my_fflush(stdout);
  359     redraw_after_suspend = FALSE;
  360 #endif /* SIGWINCH || SIGTSTP */
  361 }
  362 
  363 
  364 #ifdef SIGTSTP
  365 static void
  366 handle_suspend(
  367     void)
  368 {
  369     t_bool save_cmd_line = cmd_line;
  370     t_bool save_state = (!batch_mode || !cmd_line);
  371 
  372     TRACE(("handle_suspend(%d)", signal_context));
  373 
  374     set_keypad_off();
  375     if (!cmd_line)
  376         set_xclick_off();
  377 
  378     if (save_state) {
  379         EndWin();
  380         Raw(FALSE);
  381     }
  382 
  383     wait_message(0, _(txt_suspended_message), tin_progname);
  384 
  385     kill(0, SIGSTOP);               /* Put ourselves to sleep */
  386 
  387     RESTORE_HANDLER(SIGTSTP, signal_handler);
  388 
  389     if (save_state) {
  390         Raw(TRUE);
  391         InitWin();
  392         cmd_line = save_cmd_line;
  393         if (!cmd_line)
  394             my_retouch();
  395         need_resize = cRedraw;      /* Flag a redraw */
  396         redraw_after_suspend = TRUE;
  397     }
  398     set_keypad_on();
  399     if (!cmd_line)
  400         set_xclick_on();
  401 }
  402 #endif /* SIGTSTP */
  403 
  404 
  405 static void _CDECL
  406 signal_handler(
  407     int sig)
  408 {
  409 #ifdef SIGCHLD
  410 #   ifdef HAVE_TYPE_UNIONWAIT
  411     union wait wait_status;
  412 #   else
  413     int wait_status = 1;
  414 #   endif /* HAVE_TYPE_UNIONWAIT */
  415 #endif /* SIGCHLD */
  416 
  417     /* In this case statement, we handle only the non-fatal signals */
  418     switch (sig) {
  419 #ifdef SIGINT
  420         case SIGINT:
  421             RESTORE_HANDLER(sig, signal_handler);
  422             return;
  423 #endif /* SIGINT */
  424 
  425 /*
  426  * fatal error but we don't want the "signal handler caught signal"
  427  * message here
  428  */
  429 #if defined(HAVE_ALARM) && defined(SIGALRM)
  430         case SIGALRM:
  431 #   ifdef DEBUG
  432             if ((debug & DEBUG_NNTP) && verbose > 1)
  433                 debug_print_file("NNTP", "get_server() %d sec elapsed without response", tinrc.nntp_read_timeout_secs);
  434 #   endif /* DEBUG */
  435             tin_done(NNTP_ERROR_EXIT, _("NNTP connection error. Exiting..."));
  436             return;
  437 #endif /* HAVE_ALARM && SIGALRM */
  438 
  439 #ifdef SIGCHLD
  440         case SIGCHLD:
  441             wait(&wait_status);
  442             RESTORE_HANDLER(sig, signal_handler);   /* death of a child */
  443             system_status = WIFEXITED(wait_status) ? WEXITSTATUS(wait_status) : 0;
  444             return;
  445 #endif /* SIGCHLD */
  446 
  447 #ifdef SIGTSTP
  448         case SIGTSTP:
  449             handle_suspend();
  450             return;
  451 #endif /* SIGTSTP */
  452 
  453 #ifdef SIGWINCH
  454         case SIGWINCH:
  455             need_resize = cYes;
  456             RESTORE_HANDLER(sig, signal_handler);
  457             return;
  458 #endif /* SIGWINCH */
  459 
  460 #ifdef SIGUSR2
  461         case SIGUSR2:
  462             if (!no_write) /* TODO: add more config-files to be saved */
  463                 write_newsrc();
  464             RESTORE_HANDLER(sig, signal_handler);
  465             return;
  466 #endif /* SIGUSR2 */
  467 
  468         default:
  469             break;
  470     }
  471 
  472     fprintf(stderr, "\n%s: signal handler caught %s signal (%d).\n", tin_progname, signal_name(sig), sig);
  473 
  474     switch (sig) {
  475 #ifdef SIGHUP
  476         case SIGHUP:
  477 #endif /* SIGHUP */
  478 #ifdef SIGUSR1
  479         case SIGUSR1:
  480 #endif /* SIGUSR1 */
  481 #ifdef SIGTERM
  482         case SIGTERM:
  483 #endif /* SIGTERM */
  484 #if defined(SIGHUP) || defined(SIGUSR1) || defined(SIGTERM)
  485             dangerous_signal_exit = TRUE;
  486             tin_done(-sig, NULL);
  487             /* NOTREACHED */
  488             break;
  489 #endif /* SIGHUP || SIGUSR1 || SIGTERM */
  490 
  491 #ifdef SIGSEGV
  492         case SIGSEGV:
  493 #   if defined(SIGBUS) && (SIGSEGV != SIGBUS) /* on Haiku SIGSEGV == SIGBUS */
  494         case SIGBUS:
  495 #   endif /* SIGBUS && SIGSEGV != SIGBUS */
  496 #else
  497 #   ifdef SIGBUS
  498         case SIGBUS:
  499 #   endif /* SIGBUS */
  500 #endif /* SIGSEGV */
  501 
  502 #if defined(SIGBUS) || defined(SIGSEGV)
  503             my_fprintf(stderr, _(txt_send_bugreport), tin_progname, VERSION, RELEASEDATE, RELEASENAME, bug_addr);
  504             my_fflush(stderr);
  505             break;
  506 #endif /* SIGBUS || SIGSEGV */
  507 
  508         default:
  509             break;
  510     }
  511 
  512     cleanup_tmp_files();
  513 
  514 #if 1
  515 /* #if defined(apollo) || defined(HAVE_COREFILE) */
  516     /* do this so we can get a traceback (doesn't dump core) */
  517     abort();
  518 #else
  519     giveup();
  520 #endif /* 1 */ /* apollo || HAVE_COREFILE */
  521 }
  522 
  523 
  524 /*
  525  * Turn on (flag != FALSE) our signal handler for TSTP and WINCH
  526  * Otherwise revert to the default handler
  527  */
  528 void
  529 set_signal_catcher(
  530     int flag)
  531 {
  532 #ifdef SIGTSTP
  533     if (do_sigtstp)
  534         sigdisp(SIGTSTP, flag ? signal_handler : SIG_DFL);
  535 #endif /* SIGTSTP */
  536 
  537 #if defined(SIGWINCH) && !(defined(USE_CURSES) && defined(KEY_RESIZE))
  538     sigdisp(SIGWINCH, flag ? signal_handler : SIG_DFL);
  539 #endif /* SIGWINCH && !(USE_CURSES && KEY_RESIZE) */
  540 }
  541 
  542 
  543 void
  544 set_signal_handlers(
  545     void)
  546 {
  547     size_t n;
  548     int code;
  549 #ifdef SIGTSTP
  550     RETSIGTYPE (*ptr)(SIG_ARGS);
  551 #endif /* SIGTSTP */
  552 
  553     for (n = 0; n < ARRAY_SIZE(signal_list); n++) {
  554         switch ((code = signal_list[n].code)) {
  555 #ifdef SIGPIPE
  556         case SIGPIPE:
  557             sigdisp(code, SIG_IGN);
  558             break;
  559 #endif /* SIGPIPE */
  560 
  561 #ifdef SIGTSTP
  562         case SIGTSTP:
  563             ptr = sigdisp(code, SIG_DFL);
  564             sigdisp(code, ptr);
  565             if (ptr != SIG_IGN) {
  566                 /*
  567                  * SIGTSTP is ignored when starting from shells
  568                  * without job-control
  569                  */
  570                 do_sigtstp = TRUE;
  571                 sigdisp(code, signal_handler);
  572             }
  573             break;
  574 #endif /* SIGTSTP */
  575 
  576         default:
  577             sigdisp(code, signal_handler);
  578         }
  579     }
  580 }
  581 
  582 
  583 /*
  584  * Size the display at startup or rescale following a SIGWINCH etc.
  585  */
  586 t_bool
  587 set_win_size(
  588     int *num_lines,
  589     int *num_cols)
  590 {
  591     int old_lines;
  592     int old_cols;
  593 #ifdef TIOCGSIZE
  594     struct ttysize win;
  595 #else
  596 #   ifdef TIOCGWINSZ
  597     struct winsize win;
  598 #   endif /* TIOCGWINSZ */
  599 #endif /* TIOCGSIZE */
  600 
  601     old_lines = *num_lines;
  602     old_cols = *num_cols;
  603 
  604 #ifdef HAVE_XCURSES
  605     *num_lines = LINES - 1;     /* FIXME */
  606     *num_cols = COLS;
  607 #else /* curses/ncurses */
  608 
  609 #   ifndef USE_CURSES
  610     init_screen_array(FALSE);       /* deallocate screen array */
  611 #   endif /* !USE_CURSES */
  612 
  613 #   ifdef TIOCGSIZE
  614     if (ioctl(0, TIOCGSIZE, &win) == 0) {
  615         if (win.ts_lines != 0)
  616             *num_lines = win.ts_lines - 1;
  617         if (win.ts_cols != 0)
  618             *num_cols = win.ts_cols;
  619     }
  620 #   else
  621 #       ifdef TIOCGWINSZ
  622     if (ioctl(0, TIOCGWINSZ, &win) == 0) {
  623         if (win.ws_row != 0)
  624             *num_lines = win.ws_row - 1;
  625         if (win.ws_col != 0)
  626             *num_cols = win.ws_col;
  627     }
  628 #       else
  629 #       endif /* TIOCGWINSZ */
  630 #   endif /* TIOCGSIZE */
  631 
  632 #   ifndef USE_CURSES
  633     init_screen_array(TRUE);        /* allocate screen array for resize */
  634 #   endif /* !USE_CURSES */
  635 
  636 #endif /* HAVE_XCURSES */
  637 
  638     set_noteslines(*num_lines);
  639     return (*num_lines != old_lines || *num_cols != old_cols);
  640 }
  641 
  642 
  643 void
  644 set_noteslines(
  645     int num_lines)
  646 {
  647     NOTESLINES = num_lines - INDEX_TOP - (tinrc.beginner_level ? MINI_HELP_LINES : 1);
  648     if (NOTESLINES <= 0)
  649         NOTESLINES = 1;
  650 }