"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/src/curses.c" (12 Oct 2016, 27368 Bytes) of archive /linux/misc/tin-2.4.1.tar.gz:


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 "curses.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : curses.c
    4  *  Author    : D. Taylor & I. Lea
    5  *  Created   : 1986-01-01
    6  *  Updated   : 2013-12-06
    7  *  Notes     : This is a screen management library borrowed with permission
    8  *              from the Elm mail system. This library was hacked to provide
    9  *              what tin needs.
   10  *  Copyright : Copyright (c) 1986-99 Dave Taylor & Iain Lea
   11  *              The Elm Mail System  -  @Revision: 2.1 $   $State: Exp @
   12  */
   13 
   14 #ifndef TIN_H
   15 #   include "tin.h"
   16 #endif /* !TIN_H */
   17 #ifndef TCURSES_H
   18 #   include "tcurses.h"
   19 #endif /* !TCURSES_H */
   20 #ifndef TNNTP_H
   21 #   include "tnntp.h"
   22 #endif /* !TNNTP_H */
   23 
   24 /* local prototype */
   25 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) && defined(M_UNIX)
   26     static wint_t convert_c2wc (const char *input);
   27 #endif /* MULTIBYTE_ABLE && !NO_LOCALE && M_UNIX */
   28 
   29 #ifdef USE_CURSES
   30 
   31 #define ReadCh cmdReadCh
   32 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) && defined(M_UNIX)
   33 #   define ReadWch cmdReadWch
   34 #endif /* MULTIBYTE_ABLE && !NO_LOCALE && M_UNIX */
   35 #define get_arrow_key cmd_get_arrow_key
   36 
   37 void my_dummy(void) { } /* ANSI C requires non-empty file */
   38 t_bool have_linescroll = TRUE;  /* USE_CURSES always allows line scrolling */
   39 
   40 #else   /* !USE_CURSES */
   41 
   42 #ifndef ns32000
   43 #   undef   sinix
   44 #endif /* !ns32000 */
   45 
   46 #define DEFAULT_LINES_ON_TERMINAL   24
   47 #define DEFAULT_COLUMNS_ON_TERMINAL 80
   48 
   49 int cLINES = DEFAULT_LINES_ON_TERMINAL - 1;
   50 int cCOLS = DEFAULT_COLUMNS_ON_TERMINAL;
   51 int _hp_glitch = FALSE;     /* stdout not erased by overwriting on HP terms */
   52 static int _inraw = FALSE;  /* are we IN rawmode? */
   53 static int xclicks = FALSE; /* do we have an xterm? */
   54 t_bool have_linescroll = FALSE;
   55 
   56 #define TTYIN   0
   57 
   58 #if defined(HAVE_TERMIOS_H) && defined(HAVE_TCGETATTR) && defined(HAVE_TCSETATTR)
   59 #   ifdef HAVE_IOCTL_H
   60 #       include <ioctl.h>
   61 #   else
   62 #       ifdef HAVE_SYS_IOCTL_H
   63 #           include <sys/ioctl.h>
   64 #       endif /* HAVE_SYS_IOCTL_H */
   65 #   endif /* HAVE_IOCTL_H */
   66 #   if !defined(sun) || !defined(NL0)
   67 #       include <termios.h>
   68 #   endif /* !sun || !NL0 */
   69 #   define USE_POSIX_TERMIOS 1
   70 #   define TTY struct termios
   71 #else
   72 #   ifdef HAVE_TERMIO_H
   73 #       include <termio.h>
   74 #       define USE_TERMIO 1
   75 #       define TTY struct termio
   76 #   else
   77 #       ifdef HAVE_SGTTY_H
   78 #           include <sgtty.h>
   79 #           define USE_SGTTY 1
   80 #           define TTY struct sgttyb
   81 /*
   82     #           else
   83     #               error "No termios.h, termio.h or sgtty.h found"
   84 */
   85 #       endif /* HAVE_SGTTY_H */
   86 #   endif /* HAVE_TERMIO_H */
   87 #endif /* HAVE_TERMIOS_H && HAVE_TCGETATTR && HAVE_TCSETATTR */
   88 
   89 static TTY _raw_tty, _original_tty;
   90 
   91 
   92 #ifndef USE_SGTTY
   93 #   define USE_SGTTY 0
   94 #endif /* !USE_SGTTY */
   95 
   96 #ifndef USE_POSIX_TERMIOS
   97 #   define USE_POSIX_TERMIOS 0
   98 #   ifndef USE_TERMIO
   99 #       define USE_TERMIO 0
  100 #   endif /* !USE_TERMIO */
  101 #endif /* !USE_POSIX_TERMIOS */
  102 
  103 static char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
  104             *_setinverse, *_clearinverse, *_setunderline, *_clearunderline,
  105             *_xclickinit, *_xclickend, *_cursoron, *_cursoroff,
  106             *_terminalinit, *_terminalend, *_keypadlocal, *_keypadxmit,
  107             *_scrollregion, *_scrollfwd, *_scrollback,
  108             *_reset, *_reversevideo, *_blink, *_dim, *_bold;
  109 
  110 static int _columns, _line, _lines, _colors;
  111 
  112 #ifdef M_UNIX
  113 #   undef SET_TTY
  114 #   undef GET_TTY
  115 #   if USE_POSIX_TERMIOS
  116 #       define SET_TTY(arg) tcsetattr(TTYIN, TCSANOW, arg)
  117 #       define GET_TTY(arg) tcgetattr(TTYIN, arg)
  118 #   else
  119 #       if USE_TERMIO
  120 #           define SET_TTY(arg) ioctl(TTYIN, TCSETAW, arg)
  121 #           define GET_TTY(arg) ioctl(TTYIN, TCGETA, arg)
  122 #       else
  123 #           if USE_SGTTY
  124 #               define SET_TTY(arg) stty(TTYIN, arg)
  125 #               define GET_TTY(arg) gtty(TTYIN, arg)
  126 /*
  127     #           else
  128     #               error "No termios.h, termio.h or sgtty.h found"
  129 */
  130 #           endif /* USE_SGTTY */
  131 #       endif /* USE_TERMIO */
  132 #   endif /* USE_POSIX_TERMIOS */
  133 #endif /* M_UNIX */
  134 
  135 #if 0
  136     static int in_inverse;          /* 1 when in inverse, 0 otherwise */
  137 #endif /* 0 */
  138 
  139 /*
  140  * Local prototypes
  141  */
  142 static int input_pending(int delay);
  143 static void ScreenSize(int *num_lines, int *num_columns);
  144 static void xclick(int state);
  145 
  146 
  147 /*
  148  * returns the number of lines and columns on the display.
  149  */
  150 static void
  151 ScreenSize(
  152     int *num_lines,
  153     int *num_columns)
  154 {
  155     if (!_lines)
  156         _lines = DEFAULT_LINES_ON_TERMINAL;
  157     if (!_columns)
  158         _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  159 
  160     *num_lines = _lines - 1;        /* assume index from zero */
  161     *num_columns = _columns;        /* assume index from one */
  162 }
  163 
  164 
  165 /*
  166  * get screen size from termcap entry & setup sizes
  167  */
  168 void
  169 setup_screen(
  170     void)
  171 {
  172     _line = 1;
  173     ScreenSize(&cLINES, &cCOLS);
  174     cmd_line = FALSE;
  175     Raw(TRUE);
  176 #ifdef HAVE_COLOR
  177     bcol(tinrc.col_back);
  178 #endif /* HAVE_COLOR */
  179     set_win_size(&cLINES, &cCOLS);
  180 }
  181 
  182 #ifdef M_UNIX
  183 
  184 #   ifdef USE_TERMINFO
  185 #       define CAPNAME(a,b)       b
  186 #       define dCAPNAME(a,b)      strcpy(_terminal, b)
  187 #       define TGETSTR(b,bufp)    tigetstr(b)
  188 #       define TGETNUM(b)         tigetnum(b) /* may be tigetint() */
  189 #       define TGETFLAG(b)        tigetflag(b)
  190 #       define NO_CAP(s)          (s == 0 || s == (char *) -1)
  191 #       if !defined(HAVE_TIGETNUM) && defined(HAVE_TIGETINT)
  192 #           define tigetnum tigetint
  193 #       endif /* !HAVE_TIGETNUM && HAVE_TIGETINT */
  194 #   else /* USE_TERMCAP */
  195 #       undef USE_TERMCAP
  196 #       define USE_TERMCAP 1
  197 #       define CAPNAME(a,b)       a
  198 #       define dCAPNAME(a,b)      a
  199 #       define TGETSTR(a, bufp)   tgetstr(a, bufp)
  200 #       define TGETNUM(a)         tgetnum(a)
  201 #       define TGETFLAG(a)        tgetflag(a)
  202 #       define NO_CAP(s)          (s == 0)
  203 #   endif /* USE_TERMINFO */
  204 
  205 #   ifdef HAVE_TPARM
  206 #       define TFORMAT(fmt, a, b) tparm(fmt, b, a)
  207 #   else
  208 #       define TFORMAT(fmt, a, b) tgoto(fmt, b, a)
  209 #   endif /* HAVE_TPARM */
  210 
  211 #   ifdef HAVE_EXTERN_TCAP_PC
  212 extern char PC;         /* used in 'tputs()' */
  213 #   endif /* HAVE_EXTERN_TCAP_PC */
  214 
  215 int
  216 get_termcaps(
  217     void)
  218 {
  219     static struct {
  220         char **value;
  221         char capname[6];
  222     } table[] = {
  223         { &_clearinverse,   CAPNAME("se", "rmso") },
  224         { &_clearscreen,    CAPNAME("cl", "clear") },
  225         { &_cleartoeoln,    CAPNAME("ce", "el") },
  226         { &_cleartoeos,     CAPNAME("cd", "ed") },
  227         { &_clearunderline, CAPNAME("ue", "rmul") },
  228         { &_cursoroff,      CAPNAME("vi", "civis") },
  229         { &_cursoron,       CAPNAME("ve", "cnorm") },
  230         { &_keypadlocal,    CAPNAME("ke", "rmkx") },
  231         { &_keypadxmit,     CAPNAME("ks", "smkx") },
  232         { &_moveto,     CAPNAME("cm", "cup") },
  233         { &_scrollback,     CAPNAME("sr", "ri") },
  234         { &_scrollfwd,      CAPNAME("sf", "ind") },
  235         { &_scrollregion,   CAPNAME("cs", "csr") },
  236         { &_setinverse,     CAPNAME("so", "smso") },
  237         { &_setunderline,   CAPNAME("us", "smul") },
  238         { &_terminalend,    CAPNAME("te", "rmcup") },
  239         { &_terminalinit,   CAPNAME("ti", "smcup") },
  240         /* extra caps needed for word highlighting */
  241         { &_reset,      CAPNAME("me", "sgr0") },
  242         { &_reversevideo,   CAPNAME("mr", "rev") },
  243         { &_blink,      CAPNAME("mb", "blink") },
  244         { &_dim,        CAPNAME("mh", "dim") },
  245         { &_bold,       CAPNAME("mb", "bold") },
  246     };
  247 
  248     static char _terminal[1024];        /* Storage for terminal entry */
  249 
  250 #   if defined(USE_TERMCAP)
  251     static char _capabilities[1024];    /* String for cursor motion */
  252     static char *ptr = _capabilities;   /* for buffering */
  253 #       if defined(HAVE_EXTERN_TCAP_PC)
  254     char *t;
  255 #       endif /* HAVE_EXTERN_TCAP_PC */
  256 #   endif /* USE_TERMCAP */
  257 
  258     char the_termname[40], *p;
  259     unsigned n;
  260 
  261     if ((p = getenv("TERM")) == NULL) {
  262         my_fprintf(stderr, _(txt_no_term_set), tin_progname);
  263         return FALSE;
  264     }
  265 
  266     my_strncpy(the_termname, p, sizeof(the_termname) - 1);
  267 
  268 #   ifdef USE_TERMINFO
  269     setupterm(the_termname, fileno(stdout), (int *) 0);
  270 #   else
  271     if (tgetent(_terminal, the_termname) != 1) {
  272         my_fprintf(stderr, _(txt_cannot_get_term_entry), tin_progname);
  273         return FALSE;
  274     }
  275 #   endif /* USE_TERMINFO */
  276 
  277     /* load in all those pesky values */
  278     for (n = 0; n < ARRAY_SIZE(table); n++) {
  279         *(table[n].value) = TGETSTR(table[n].capname, &ptr);
  280     }
  281     _lines = TGETNUM(dCAPNAME("li", "lines"));
  282     _colors = TGETNUM(dCAPNAME("Co", "colors"));
  283     _columns = TGETNUM(dCAPNAME("co", "cols"));
  284     _hp_glitch = TGETFLAG(dCAPNAME("xs", "xhp"));
  285 
  286 #   if defined(USE_TERMCAP) && defined(HAVE_EXTERN_TCAP_PC)
  287     t = TGETSTR(CAPNAME("pc", "pad"), &p);
  288     if (t != 0)
  289         PC = *t;
  290 #   endif /* USE_TERMCAP && HAVE_EXTERN_TCAP_PC */
  291 
  292     if (STRCMPEQ(the_termname, "xterm")) {
  293         static char x_init[] = "\033[?9h";
  294         static char x_end[] = "\033[?9l";
  295         xclicks = TRUE;
  296         _xclickinit = x_init;
  297         _xclickend = x_end;
  298     }
  299 
  300     if (NO_CAP(_clearscreen)) {
  301         my_fprintf(stderr, _(txt_no_term_clearscreen), tin_progname);
  302         return FALSE;
  303     }
  304     if (NO_CAP(_moveto)) {
  305         my_fprintf(stderr, _(txt_no_term_cursor_motion), tin_progname);
  306         return FALSE;
  307     }
  308     if (NO_CAP(_cleartoeoln)) {
  309         my_fprintf(stderr, _(txt_no_term_clear_eol), tin_progname);
  310         return FALSE;
  311     }
  312     if (NO_CAP(_cleartoeos)) {
  313         my_fprintf(stderr, _(txt_no_term_clear_eos), tin_progname);
  314         return FALSE;
  315     }
  316     if (_lines == -1)
  317         _lines = DEFAULT_LINES_ON_TERMINAL;
  318     if (_columns == -1)
  319         _columns = DEFAULT_COLUMNS_ON_TERMINAL;
  320 
  321     if (_lines < MIN_LINES_ON_TERMINAL || _columns < MIN_COLUMNS_ON_TERMINAL) {
  322         my_fprintf(stderr, _(txt_screen_too_small), tin_progname);
  323         return FALSE;
  324     }
  325     /*
  326      * kludge to workaround no inverse
  327      */
  328     if (NO_CAP(_setinverse)) {
  329         _setinverse = _setunderline;
  330         _clearinverse = _clearunderline;
  331         if (NO_CAP(_setinverse))
  332             tinrc.draw_arrow = 1;
  333     }
  334     if (NO_CAP(_scrollregion) || NO_CAP(_scrollfwd) || NO_CAP(_scrollback))
  335         have_linescroll = FALSE;
  336     else
  337         have_linescroll = TRUE;
  338     return TRUE;
  339 }
  340 
  341 
  342 int
  343 InitScreen(
  344     void)
  345 {
  346     InitWin();
  347 #   ifdef HAVE_COLOR
  348     postinit_colors(MAX(_colors, MAX_COLOR + 1)); /* postinit_colors(_colors) would be correct */
  349 #   endif /* HAVE_COLOR */
  350     return TRUE;
  351 }
  352 
  353 #else   /* !M_UNIX */
  354 
  355 int
  356 InitScreen(
  357     void)
  358 {
  359     char *ptr;
  360 
  361     /*
  362      * we're going to assume a terminal here...
  363      */
  364 
  365     _clearscreen = "\033[1;1H\033[J";
  366     _moveto = "\033[%d;%dH";    /* not a termcap string! */
  367     _cleartoeoln = "\033[K";
  368     _setinverse = "\033[7m";
  369     _clearinverse = "\033[0m";
  370     _setunderline = "\033[4m";
  371     _clearunderline = "\033[0m";
  372     _keypadlocal = "";
  373     _keypadxmit = "";
  374     /* needed for word highlighting */
  375     _reset = "\033[0m";
  376     _reversevideo = "\033[7m";
  377     _blink = "\033[5m";
  378     _dim = "\033[2m";
  379     _bold = "\033[1m";
  380 
  381     _lines = _columns = -1;
  382 
  383     if ((ptr = getenv("LINES")) != 0)
  384         _lines = atol(ptr);
  385 
  386     if ((ptr = getenv("COLUMNS")) != 0)
  387         _columns = atol(ptr);
  388 
  389     /*
  390      * If that failed, try get a response from the console itself
  391      */
  392 
  393     if (_lines < MIN_LINES_ON_TERMINAL || _columns < MIN_COLUMNS_ON_TERMINAL) {
  394         my_fprintf(stderr, _(txt_screen_too_small), tin_progname);
  395         return FALSE;
  396     }
  397 
  398     InitWin();
  399 
  400     Raw(FALSE);
  401 
  402     have_linescroll = FALSE;
  403     return TRUE;
  404 }
  405 
  406 #endif /* M_UNIX */
  407 
  408 
  409 void
  410 InitWin(
  411     void)
  412 {
  413     if (_terminalinit) {
  414         tputs(_terminalinit, 1, outchar);
  415         my_flush();
  416     }
  417     set_keypad_on();
  418     set_xclick_on();
  419 }
  420 
  421 
  422 void
  423 EndWin(
  424     void)
  425 {
  426     if (_terminalend) {
  427         tputs(_terminalend, 1, outchar);
  428         my_flush();
  429     }
  430     set_keypad_off();
  431     set_xclick_off();
  432 }
  433 
  434 
  435 void
  436 set_keypad_on(
  437     void)
  438 {
  439 #   ifdef HAVE_KEYPAD
  440     if (tinrc.use_keypad && _keypadxmit) {
  441         tputs(_keypadxmit, 1, outchar);
  442         my_flush();
  443     }
  444 #   endif /* HAVE_KEYPAD */
  445 }
  446 
  447 
  448 void
  449 set_keypad_off(
  450     void)
  451 {
  452 #   ifdef HAVE_KEYPAD
  453     if (tinrc.use_keypad && _keypadlocal) {
  454         tputs(_keypadlocal, 1, outchar);
  455         my_flush();
  456     }
  457 #   endif /* HAVE_KEYPAD */
  458 }
  459 
  460 
  461 /*
  462  * clear the screen
  463  */
  464 void
  465 ClearScreen(
  466     void)
  467 {
  468 #ifdef HAVE_COLOR
  469     fcol(tinrc.col_normal);
  470     bcol(tinrc.col_back);
  471 #endif /* HAVE_COLOR */
  472     tputs(_clearscreen, 1, outchar);
  473     my_flush();     /* clear the output buffer */
  474     _line = 1;
  475 }
  476 
  477 
  478 #ifdef HAVE_COLOR
  479 void
  480 reset_screen_attr(
  481     void)
  482 {
  483     if (!NO_CAP(_reset)) {
  484         tputs(_reset, 1, outchar);
  485         my_flush();
  486     }
  487 }
  488 #endif /* HAVE_COLOR */
  489 
  490 
  491 /*
  492  *  move cursor to the specified row column on the screen.
  493  *  0,0 is the top left!
  494  */
  495 #ifdef M_UNIX
  496 void
  497 MoveCursor(
  498     int row,
  499     int col)
  500 {
  501     char *stuff;
  502 
  503     stuff = tgoto(_moveto, col, row);
  504     tputs(stuff, 1, outchar);
  505     my_flush();
  506     _line = row + 1;
  507 }
  508 
  509 #else   /* !M_UNIX */
  510 
  511 void
  512 MoveCursor(
  513     int row,
  514     int col)
  515 {
  516     char stuff[12];
  517 
  518     if (_moveto) {
  519         snprintf(stuff, sizeof(stuff), _moveto, row + 1, col + 1);
  520         tputs(stuff, 1, outchar);
  521         my_flush();
  522         _line = row + 1;
  523     }
  524 }
  525 #endif /* M_UNIX */
  526 
  527 
  528 /*
  529  * clear to end of line
  530  */
  531 void
  532 CleartoEOLN(
  533     void)
  534 {
  535     tputs(_cleartoeoln, 1, outchar);
  536     my_flush(); /* clear the output buffer */
  537 }
  538 
  539 
  540 /*
  541  * clear to end of screen
  542  */
  543 void
  544 CleartoEOS(
  545     void)
  546 {
  547     int i;
  548 
  549     if (_cleartoeos) {
  550         tputs(_cleartoeos, 1, outchar);
  551     } else {
  552         for (i = _line - 1; i < _lines; i++) {
  553             MoveCursor(i, 0);
  554             CleartoEOLN();
  555         }
  556     }
  557     my_flush(); /* clear the output buffer */
  558 }
  559 
  560 
  561 static int _topscrregion, _bottomscrregion;
  562 
  563 void
  564 SetScrollRegion(
  565     int topline,
  566     int bottomline)
  567 {
  568     char *stuff;
  569 
  570     if (!have_linescroll)
  571         return;
  572     if (_scrollregion) {
  573         stuff = TFORMAT(_scrollregion, topline, bottomline);
  574         tputs(stuff, 1, outchar);
  575         _topscrregion = topline;
  576         _bottomscrregion = bottomline;
  577     }
  578     my_flush();
  579 }
  580 
  581 
  582 void
  583 ScrollScreen(
  584     int lines_to_scroll)
  585 {
  586     int i;
  587 
  588     if (!have_linescroll || (lines_to_scroll == 0))
  589         return;
  590     if (lines_to_scroll < 0) {
  591         if (_scrollback) {
  592             i = lines_to_scroll;
  593             while (i++) {
  594                 MoveCursor(_topscrregion, 0);
  595                 tputs(_scrollback, 1, outchar);
  596             }
  597         }
  598     } else
  599         if (_scrollfwd) {
  600             i = lines_to_scroll;
  601             while (i--) {
  602                 MoveCursor(_bottomscrregion, 0);
  603                 tputs(_scrollfwd, 1, outchar);
  604             }
  605         }
  606     my_flush();
  607 }
  608 
  609 
  610 /*
  611  * set inverse video mode
  612  */
  613 void
  614 StartInverse(
  615     void)
  616 {
  617 /*  in_inverse = 1; */
  618     if (_setinverse && tinrc.inverse_okay) {
  619 #   ifdef HAVE_COLOR
  620         if (use_color) {
  621             bcol(tinrc.col_invers_bg);
  622             fcol(tinrc.col_invers_fg);
  623         } else {
  624             tputs(_setinverse, 1, outchar);
  625         }
  626 #   else
  627         tputs(_setinverse, 1, outchar);
  628 #   endif /* HAVE_COLOR */
  629     }
  630     my_flush();
  631 }
  632 
  633 
  634 /*
  635  * compliment of startinverse
  636  */
  637 void
  638 EndInverse(
  639     void)
  640 {
  641 /*  in_inverse = 0; */
  642     if (_clearinverse && tinrc.inverse_okay) {
  643 #   ifdef HAVE_COLOR
  644         if (use_color) {
  645             fcol(tinrc.col_normal);
  646             bcol(tinrc.col_back);
  647         } else {
  648             tputs(_clearinverse, 1, outchar);
  649         }
  650 #   else
  651         tputs(_clearinverse, 1, outchar);
  652 #   endif /* HAVE_COLOR */
  653     }
  654     my_flush();
  655 }
  656 
  657 
  658 #if 0 /* doesn't work correct with ncurses4.x */
  659 /*
  660  * toggle inverse video mode
  661  */
  662 void
  663 ToggleInverse(
  664     void)
  665 {
  666     if (!in_inverse)
  667         StartInverse();
  668     else
  669         EndInverse();
  670 }
  671 #endif /* 0 */
  672 
  673 
  674 /*
  675  * returns either 1 or 0, for ON or OFF
  676  */
  677 int
  678 RawState(
  679     void)
  680 {
  681     return _inraw;
  682 }
  683 
  684 
  685 /*
  686  * state is either TRUE or FALSE, as indicated by call
  687  */
  688 void
  689 Raw(
  690     int state)
  691 {
  692     if (!state && _inraw) {
  693         SET_TTY(&_original_tty);
  694         _inraw = 0;
  695     } else if (state && !_inraw) {
  696         GET_TTY(&_original_tty);
  697         GET_TTY(&_raw_tty);
  698 #if USE_SGTTY
  699         _raw_tty.sg_flags &= ~(ECHO | CRMOD);   /* echo off */
  700         _raw_tty.sg_flags |= CBREAK;        /* raw on */
  701 #else
  702 #   ifdef __FreeBSD__
  703         cfmakeraw(&_raw_tty);
  704         _raw_tty.c_lflag |= ISIG;       /* for ^Z */
  705 #   else
  706         _raw_tty.c_lflag &= ~(ICANON | ECHO);   /* noecho raw mode */
  707         _raw_tty.c_cc[VMIN] = '\01';    /* minimum # of chars to queue */
  708         _raw_tty.c_cc[VTIME] = '\0';    /* minimum time to wait for input */
  709 #   endif /* __FreeBSD__ */
  710 #endif /* USE_SGTTY */
  711         SET_TTY(&_raw_tty);
  712         _inraw = 1;
  713     }
  714 }
  715 
  716 
  717 /*
  718  *  output a character. From tputs... (Note: this CANNOT be a macro!)
  719  */
  720 OUTC_FUNCTION(
  721     outchar)
  722 {
  723 #ifdef OUTC_RETURN
  724     return fputc(c, stdout);
  725 #else
  726     (void) fputc(c, stdout);
  727 #endif /* OUTC_RETURN */
  728 }
  729 
  730 
  731 /*
  732  * setup to monitor mouse buttons if running in a xterm
  733  */
  734 static void
  735 xclick(
  736     int state)
  737 {
  738     static int prev_state = 999;
  739 
  740     if (xclicks && prev_state != state) {
  741         if (state) {
  742             tputs(_xclickinit, 1, outchar);
  743         } else {
  744             tputs(_xclickend, 1, outchar);
  745         }
  746         my_flush();
  747         prev_state = state;
  748     }
  749 }
  750 
  751 
  752 /*
  753  * switch on monitoring of mouse buttons
  754  */
  755 void
  756 set_xclick_on(
  757     void)
  758 {
  759     if (tinrc.use_mouse)
  760         xclick(TRUE);
  761 }
  762 
  763 
  764 /*
  765  * switch off monitoring of mouse buttons
  766  */
  767 void
  768 set_xclick_off(
  769     void)
  770 {
  771     if (tinrc.use_mouse)
  772         xclick(FALSE);
  773 }
  774 
  775 
  776 void
  777 cursoron(
  778     void)
  779 {
  780     if (_cursoron)
  781         tputs(_cursoron, 1, outchar);
  782 }
  783 
  784 
  785 void
  786 cursoroff(
  787     void)
  788 {
  789     if (_cursoroff)
  790         tputs(_cursoroff, 1, outchar);
  791 }
  792 
  793 
  794 /*
  795  * Inverse 'size' chars at (row,col)
  796  */
  797 void
  798 highlight_string(
  799     int row,
  800     int col,
  801     int size)
  802 {
  803     char output[LEN];
  804 
  805     my_strncpy(output, &(screen[row].col[col]), size);
  806 
  807 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  808     /*
  809      * In a multibyte locale we get byte offsets instead of character
  810      * offsets; calculate now the correct starting column
  811      */
  812     if (col > 0) {
  813         char tmp[LEN];
  814         wchar_t *wtmp;
  815 
  816         my_strncpy(tmp, &(screen[row].col[0]), sizeof(tmp) - 1);
  817         tmp[col] = '\0';
  818         if ((wtmp = char2wchar_t(tmp)) != NULL) {
  819             col = wcswidth(wtmp, wcslen(wtmp) + 1);
  820             free(wtmp);
  821         }
  822     }
  823 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  824 
  825     MoveCursor(row, col);
  826     StartInverse();
  827     my_fputs(output, stdout);
  828     EndInverse();
  829     my_flush();
  830 
  831     stow_cursor();
  832 }
  833 
  834 
  835 /*
  836  * Color 'size' chars at (row,col) with 'color' and handle marks
  837  */
  838 void
  839 word_highlight_string(
  840     int row,
  841     int col,
  842     int size,
  843     int color)
  844 {
  845     /*
  846      * Mapping of the tinrc.mono_mark* values to the corresponding escape sequences
  847      */
  848     char *attributes[MAX_ATTR + 1];
  849     char *dest, *src;
  850     char output[LEN];
  851     int byte_offset = col;
  852     int wsize = size;
  853 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  854     wchar_t *wtmp;
  855 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  856 
  857     attributes[0] = _reset; /* Normal */
  858     attributes[1] = _setinverse;    /* Best highlighting */
  859     attributes[2] = _setunderline;  /* Underline */
  860     attributes[3] = _reversevideo;  /* Reverse video */
  861     attributes[4] = _blink; /* Blink */
  862     attributes[5] = _dim;   /* Dim */
  863     attributes[6] = _bold;  /* Bold */
  864 
  865     my_strncpy(output, &(screen[row].col[byte_offset]), size);
  866 
  867 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  868     /*
  869      * In a multibyte locale we get byte offsets instead of character
  870      * offsets; calculate now the correct starting column and
  871      * width
  872      */
  873     if (byte_offset > 0) {
  874         char tmp[LEN];
  875         my_strncpy(tmp, &(screen[row].col[0]), sizeof(tmp) - 1);
  876         tmp[byte_offset] = '\0';
  877         if ((wtmp = char2wchar_t(tmp)) != NULL) {
  878             col = wcswidth(wtmp, wcslen(wtmp) + 1);
  879             free(wtmp);
  880         }
  881     }
  882     if ((wtmp = char2wchar_t(output)) != NULL) {
  883         wsize = wcswidth(wtmp, wcslen(wtmp) + 1);
  884         free(wtmp);
  885     }
  886 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  887 
  888     MoveCursor(row, col);
  889 
  890     /* safeguard against bogus regexps */
  891     if ((output[0] == '*' && output[size - 1] == '*') ||
  892          (output[0] == '/' && output[size - 1] == '/') ||
  893          (output[0] == '_' && output[size - 1] == '_') ||
  894          (output[0] == '-' && output[size - 1] == '-')) {
  895 
  896         switch (tinrc.word_h_display_marks) {
  897             case 0: /* remove marks */
  898                 MoveCursor(row, col + wsize - 2);
  899                 CleartoEOLN();
  900                 my_fputs(&(screen[row].col[byte_offset + size]), stdout);
  901                 output[0] = output[size - 1] = ' ';
  902                 str_trim(output);
  903                 strncpy(&(screen[row].col[byte_offset]), output, size - 2);
  904                 src = &(screen[row].col[byte_offset + size]);
  905                 dest = &(screen[row].col[byte_offset + size - 2]);
  906                 while (*src)
  907                     *dest++ = *src++;
  908                 *dest++ = '\0';
  909                 MoveCursor(row, col);
  910                 break;
  911 
  912             case 2: /* print space */
  913                 MoveCursor(row, col + wsize - 1);
  914                 my_fputs(" ", stdout);
  915                 MoveCursor(row, col);
  916                 my_fputs(" ", stdout);
  917                 output[0] = output[size - 1] = ' ';
  918                 str_trim(output);
  919                 screen[row].col[byte_offset] = ' ';
  920                 screen[row].col[byte_offset + size - 1] = ' ';
  921                 break;
  922 
  923             default:    /* print mark (case 1) */
  924                 break;
  925         }
  926     }
  927 #   ifdef HAVE_COLOR
  928     if (use_color)
  929         fcol(color);
  930     else
  931 #   endif /* HAVE_COLOR */
  932         if (color > 0 && color <= MAX_ATTR && !NO_CAP(attributes[color]))
  933             tputs(attributes[color], 1, outchar);
  934     my_fputs(output, stdout);
  935     my_flush();
  936 #   ifdef HAVE_COLOR
  937     if (use_color)
  938         fcol(tinrc.col_text);
  939     else
  940 #   endif /* HAVE_COLOR */
  941         if (!NO_CAP(_reset))
  942             tputs(_reset, 1, outchar);
  943     stow_cursor();
  944 }
  945 #endif /* USE_CURSES */
  946 
  947 
  948 /*
  949  * input_pending() waits for input during time given
  950  * by delay in msec. The original behavior of input_pending()
  951  * (in art.c's threading code) is delay=0
  952  */
  953 static int
  954 input_pending(
  955     int delay)
  956 {
  957 #if 0
  958     int ch;
  959 
  960     nodelay(stdscr, TRUE);
  961     if ((ch = getch()) != ERR)
  962         ungetch(ch);
  963     nodelay(stdscr, FALSE);
  964     return (ch != ERR);
  965 
  966 #else
  967 
  968 #   ifdef HAVE_SELECT
  969     int fd = STDIN_FILENO;
  970     fd_set fdread;
  971     struct timeval tvptr;
  972 
  973     FD_ZERO(&fdread);
  974 
  975     tvptr.tv_sec = 0;
  976     tvptr.tv_usec = delay * 100;
  977 
  978     FD_SET(fd, &fdread);
  979 
  980 #       ifdef HAVE_SELECT_INTP
  981     if (select(1, (int *) &fdread, NULL, NULL, &tvptr))
  982 #       else
  983     if (select(1, &fdread, NULL, NULL, &tvptr))
  984 #       endif /* HAVE_SELECT_INTP */
  985     {
  986         if (FD_ISSET(fd, &fdread))
  987             return TRUE;
  988     }
  989 #   endif /* HAVE_SELECT */
  990 
  991 #   if defined(HAVE_POLL) && !defined(HAVE_SELECT)
  992     static int Timeout;
  993     static long nfds = 1;
  994     static struct pollfd fds[] = {{ STDIN_FILENO, POLLIN, 0 }};
  995 
  996     Timeout = delay;
  997     if (poll(fds, nfds, Timeout) < 0) /* Error on poll */
  998         return FALSE;
  999 
 1000     switch (fds[0].revents) {
 1001         case POLLIN:
 1002             return TRUE;
 1003         /*
 1004          * Other conditions on the stream
 1005          */
 1006         case POLLHUP:
 1007         case POLLERR:
 1008         default:
 1009             return FALSE;
 1010     }
 1011 #   endif /* HAVE_POLL && !HAVE_SELECT */
 1012 
 1013 #endif /* 0 */
 1014 
 1015     return FALSE;
 1016 }
 1017 
 1018 
 1019 #if defined(HAVE_USLEEP) || defined(HAVE_SELECT) || defined(HAVE_POLL)
 1020 #   define wait_a_while(i) \
 1021     while (!input_pending(0) \
 1022         && i < ((VT_ESCAPE_TIMEOUT * 1000) / SECOND_CHARACTER_DELAY))
 1023 #endif /* HAVE_USLEEP || HAVE_SELECT || HAVE_POLL */
 1024 int
 1025 get_arrow_key(
 1026     int prech)
 1027 {
 1028     int ch;
 1029     int ch1;
 1030 #if defined(HAVE_USLEEP) || defined(HAVE_SELECT) || defined(HAVE_POLL)
 1031     int i = 0;
 1032 #endif /* HAVE_USLEEP || HAVE_SELECT || HAVE_POLL */
 1033 
 1034     if (!input_pending(0)) {
 1035 #   ifdef HAVE_USLEEP
 1036         wait_a_while(i) {
 1037             usleep((unsigned long) (SECOND_CHARACTER_DELAY * 1000));
 1038             i++;
 1039         }
 1040 #   else    /* !HAVE_USLEEP */
 1041 #       ifdef HAVE_SELECT
 1042         struct timeval tvptr;
 1043 
 1044         wait_a_while(i) {
 1045             tvptr.tv_sec = 0;
 1046             tvptr.tv_usec = SECOND_CHARACTER_DELAY * 1000;
 1047             select(0, NULL, NULL, NULL, &tvptr);
 1048             i++;
 1049         }
 1050 #       else /* !HAVE_SELECT */
 1051 #           ifdef HAVE_POLL
 1052         struct pollfd fds[1];
 1053 
 1054         wait_a_while(i) {
 1055             poll(fds, 0, SECOND_CHARACTER_DELAY);
 1056             i++;
 1057         }
 1058 #           else /* !HAVE_POLL */
 1059         (void) sleep(1);
 1060 #           endif /* HAVE_POLL */
 1061 #       endif /* HAVE_SELECT */
 1062 #   endif /* HAVE_USLEEP */
 1063         if (!input_pending(0))
 1064             return prech;
 1065     }
 1066     ch = ReadCh();
 1067     if (ch == '[' || ch == 'O')
 1068         ch = ReadCh();
 1069 
 1070     switch (ch) {
 1071         case 'A':
 1072         case 'i':
 1073 #   ifdef QNX42
 1074         case 0xA1:
 1075 #   endif /* QNX42 */
 1076             return KEYMAP_UP;
 1077 
 1078         case 'B':
 1079 #   ifdef QNX42
 1080         case 0xA9:
 1081 #   endif /* QNX42 */
 1082             return KEYMAP_DOWN;
 1083 
 1084         case 'D':
 1085 #   ifdef QNX42
 1086         case 0xA4:
 1087 #   endif /* QNX42 */
 1088             return KEYMAP_LEFT;
 1089 
 1090         case 'C':
 1091 #   ifdef QNX42
 1092         case 0xA6:
 1093 #   endif /* QNX42 */
 1094             return KEYMAP_RIGHT;
 1095 
 1096         case 'I':       /* ansi  PgUp */
 1097         case 'V':       /* at386 PgUp */
 1098         case 'S':       /* 97801 PgUp */
 1099         case 'v':       /* emacs style */
 1100 #   ifdef QNX42
 1101         case 0xA2:
 1102 #   endif /* QNX42 */
 1103             return KEYMAP_PAGE_UP;
 1104 
 1105         case 'G':       /* ansi  PgDn */
 1106         case 'U':       /* at386 PgDn */
 1107         case 'T':       /* 97801 PgDn */
 1108 #   ifdef QNX42
 1109         case 0xAA:
 1110 #   endif /* QNX42 */
 1111             return KEYMAP_PAGE_DOWN;
 1112 
 1113         case 'H':       /* at386 Home */
 1114 #   ifdef QNX42
 1115         case 0xA0:
 1116 #   endif /* QNX42 */
 1117             return KEYMAP_HOME;
 1118 
 1119         case 'F':       /* ansi  End */
 1120         case 'Y':       /* at386 End */
 1121 #   ifdef QNX42
 1122         case 0xA8:
 1123 #   endif /* QNX42 */
 1124             return KEYMAP_END;
 1125 
 1126         case '2':       /* vt200 Ins */
 1127             (void) ReadCh();    /* eat the ~ */
 1128             return KEYMAP_INS;
 1129 
 1130         case '3':       /* vt200 Del */
 1131             (void) ReadCh();    /* eat the ~ */
 1132             return KEYMAP_DEL;
 1133 
 1134         case '5':       /* vt200 PgUp */
 1135             (void) ReadCh();    /* eat the ~ (interesting use of words :) */
 1136             return KEYMAP_PAGE_UP;
 1137 
 1138         case '6':       /* vt200 PgUp */
 1139             (void) ReadCh();    /* eat the ~ */
 1140             return KEYMAP_PAGE_DOWN;
 1141 
 1142         case '1':       /* vt200 PgUp */
 1143             ch = ReadCh(); /* eat the ~ */
 1144             if (ch == '5') {    /* RS/6000 PgUp is 150g, PgDn is 154g */
 1145                 ch1 = ReadCh();
 1146                 (void) ReadCh();
 1147                 if (ch1 == '0')
 1148                     return KEYMAP_PAGE_UP;
 1149                 if (ch1 == '4')
 1150                     return KEYMAP_PAGE_DOWN;
 1151             }
 1152             return KEYMAP_HOME;
 1153 
 1154         case '4':       /* vt200 PgUp */
 1155             (void) ReadCh();    /* eat the ~ */
 1156             return KEYMAP_END;
 1157 
 1158         case 'M':       /* xterminal button press */
 1159             xmouse = ReadCh() - ' ';    /* button */
 1160             xcol = ReadCh() - '!';      /* column */
 1161             xrow = ReadCh() - '!';      /* row */
 1162             return KEYMAP_MOUSE;
 1163 
 1164         default:
 1165             return KEYMAP_UNKNOWN;
 1166     }
 1167 }
 1168 
 1169 
 1170 /*
 1171  * The UNIX version of ReadCh, termcap version
 1172  */
 1173 #ifdef M_UNIX
 1174 int
 1175 ReadCh(
 1176     void)
 1177 {
 1178     int result;
 1179 #   ifndef READ_CHAR_HACK
 1180     char ch;
 1181 #   endif /* !READ_CHAR_HACK */
 1182 
 1183     fflush(stdout);
 1184 #   ifdef READ_CHAR_HACK
 1185 #       undef getc
 1186     while ((result = getc(stdin)) == EOF) {
 1187         if (feof(stdin))
 1188             break;
 1189 
 1190 #       ifdef EINTR
 1191         if (ferror(stdin) && errno != EINTR)
 1192 #       else
 1193         if (ferror(stdin))
 1194 #       endif /* EINTR */
 1195             break;
 1196 
 1197         clearerr(stdin);
 1198     }
 1199 
 1200     return ((result == EOF) ? EOF : result & 0xFF);
 1201 
 1202 #   else
 1203 #       ifdef EINTR
 1204 
 1205     allow_resize(TRUE);
 1206     while ((result = read(0, &ch, 1)) < 0 && errno == EINTR) {      /* spin on signal interrupts */
 1207         if (need_resize) {
 1208             handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
 1209             need_resize = cNo;
 1210         }
 1211     }
 1212     allow_resize(FALSE);
 1213 #       else
 1214     result = read(0, &ch, 1);
 1215 #       endif /* EINTR */
 1216 
 1217     return ((result <= 0) ? EOF : ch & 0xFF);
 1218 
 1219 #   endif /* READ_CHAR_HACK */
 1220 }
 1221 
 1222 
 1223 #   if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
 1224 /*
 1225  * A helper function for ReadWch()
 1226  * converts the read input to a wide-char
 1227  */
 1228 static wint_t
 1229 convert_c2wc(
 1230     const char *input)
 1231 {
 1232     int res;
 1233     wchar_t wc;
 1234 
 1235     res = mbtowc(&wc, input, MB_CUR_MAX);
 1236     if (res == -1)
 1237         return WEOF;
 1238     else
 1239         return (wint_t) wc;
 1240 }
 1241 
 1242 
 1243 wint_t
 1244 ReadWch(
 1245     void)
 1246 {
 1247     char *mbs = my_malloc(MB_CUR_MAX + 1);
 1248     int result, to_read;
 1249     wchar_t wch;
 1250 
 1251     fflush(stdout);
 1252 
 1253     /*
 1254      * Independent of the pressed key and the used charset we have to
 1255      * read at least one byte. The further processing is depending of
 1256      * the read byte and the used charset.
 1257      */
 1258 #       ifdef EINTR
 1259     allow_resize(TRUE);
 1260     while ((result = read(0, mbs, 1)) < 0 && errno == EINTR) { /* spin on signal interrupts */
 1261         if (need_resize) {
 1262             handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
 1263             need_resize = cNo;
 1264         }
 1265     }
 1266     allow_resize(FALSE);
 1267 #       else
 1268     result = read(0, mbs, 1);
 1269 #       endif /* EINTR */
 1270 
 1271     if (result <= 0) {
 1272         free(mbs);
 1273         return WEOF;
 1274     }
 1275 
 1276     /* Begin of an ESC-sequence. Let get_arrow_key() figure out which it is */
 1277     if (mbs[0] == ESC) {
 1278         free(mbs);
 1279         return (wint_t) ESC;
 1280     }
 1281 
 1282     /*
 1283      * In an one-byte charset we don't need to read further chars but
 1284      * we still need to convert the char to a correct wide-char
 1285      */
 1286     if (MB_CUR_MAX == 1) {
 1287         mbs[1] = '\0';
 1288         wch = convert_c2wc(mbs);
 1289         free(mbs);
 1290 
 1291         return (wint_t) wch;
 1292     }
 1293 
 1294     /*
 1295      * we use a multi-byte charset
 1296      */
 1297 
 1298     /*
 1299      * UTF-8
 1300      */
 1301     if (!strcasecmp(tinrc.mm_local_charset, "UTF-8")) {
 1302         int ch = mbs[0] & 0xFF;
 1303 
 1304         /* determine the count of bytes we have still have to read */
 1305         if (ch <= 0x7F) {
 1306             /* ASCII char */
 1307             to_read = 0;
 1308         } else if (ch >= 0xC2 && ch <= 0xDF) {
 1309             /* 2-byte sequence */
 1310             to_read = 1;
 1311         } else if (ch >= 0xE0 && ch <= 0xEF) {
 1312             /* 3-byte sequence */
 1313             to_read = 2;
 1314         } else if (ch >= 0xF0 && ch <= 0xF4) {
 1315             /* 4-byte sequence */
 1316             to_read = 3;
 1317         } else {
 1318             /* invalid sequence */
 1319             free(mbs);
 1320             return WEOF;
 1321         }
 1322 
 1323         /* read the missing bytes of the multi-byte sequence */
 1324         if (to_read > 0) {
 1325 #       ifdef EINTR
 1326             allow_resize(TRUE);
 1327             while ((result = read(0, mbs + 1, to_read)) < 0 && errno == EINTR) { /* spin on signal interrupts */
 1328                 if (need_resize) {
 1329                     handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
 1330                     need_resize = cNo;
 1331                 }
 1332             }
 1333             allow_resize(FALSE);
 1334 #       else
 1335             result = read(0, mbs + 1, to_read);
 1336 #       endif /* EINTR */
 1337             if (result < 0) {
 1338                 free(mbs);
 1339 
 1340                 return WEOF;
 1341             }
 1342         }
 1343         mbs[to_read + 1] = '\0';
 1344         wch = convert_c2wc(mbs);
 1345         free (mbs);
 1346 
 1347         return (wint_t) wch;
 1348 
 1349     }
 1350 
 1351     /* FIXME: add support for other multi-byte charsets */
 1352 
 1353     free(mbs);
 1354     return WEOF;
 1355 }
 1356 #   endif /* MULTIBYTE_ABLE && !NO_LOCALE */
 1357 #endif /* M_UNIX */