"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.4/src/tcurses.c" (20 Nov 2019, 17681 Bytes) of package /linux/misc/tin-2.4.4.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 "tcurses.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.3_vs_2.4.4.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : tcurses.c
    4  *  Author    : Thomas Dickey <dickey@invisible-island.net>
    5  *  Created   : 1997-03-02
    6  *  Updated   : 2018-07-02
    7  *  Notes     : This is a set of wrapper functions adapting the termcap
    8  *               interface of tin to use SVr4 curses (e.g., ncurses).
    9  *
   10  * Copyright (c) 1997-2020 Thomas Dickey <dickey@invisible-island.net>
   11  * All rights reserved.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  *
   17  * 1. Redistributions of source code must retain the above copyright notice,
   18  *    this list of conditions and the following disclaimer.
   19  *
   20  * 2. Redistributions in binary form must reproduce the above copyright
   21  *    notice, this list of conditions and the following disclaimer in the
   22  *    documentation and/or other materials provided with the distribution.
   23  *
   24  * 3. Neither the name of the copyright holder nor the names of its
   25  *    contributors may be used to endorse or promote products derived from
   26  *    this software without specific prior written permission.
   27  *
   28  * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   29  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   31  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   32  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 
   42 #ifndef TIN_H
   43 #   include "tin.h"
   44 #endif /* !TIN_H */
   45 #ifndef TCURSES_H
   46 #   include "tcurses.h"
   47 #endif /* !TCURSES_H */
   48 
   49 #ifdef USE_CURSES
   50 
   51 #   ifndef KEY_MIN
   52 #       define KEY_MIN KEY_BREAK    /* SVr3 curses */
   53 #   endif /* !KEY_MIN */
   54 
   55 #   ifndef KEY_CODE_YES
   56 #       define KEY_CODE_YES (KEY_MIN - 1)   /* PDCurses */
   57 #   endif /* !KEY_CODE_YES */
   58 
   59 #   include "trace.h"
   60 
   61 int cLINES;
   62 int cCOLS;
   63 
   64 static int my_innstr(char *str, int n);
   65 
   66 
   67 #   if defined(HAVE_XCURSES) && !defined(HAVE_VW_PRINTW)
   68 static int
   69 vw_printw(
   70     WINDOW *w,
   71     char *fmt,
   72     va_list ap)
   73 {
   74     char buffer[BUFSIZ];    /* FIXME */
   75     char *string = buffer;
   76     int y, x, code;
   77 
   78     vsnprintf(buffer, sizeof(buffer), fmt, ap);
   79     getyx(w, y, x);
   80     TRACE(("vw_printw[%d/%d,%d/%d]:%s", y, cLINES, x, cCOLS, buffer));
   81     while (*string == '\b')
   82         string++;
   83     code = waddstr(w, string);
   84     if (string != buffer) {
   85         wmove(w, y, x);
   86         refresh();
   87     }
   88     return code;
   89 }
   90 #   endif /* HAVE_XCURSES && !HAVE_VW_PRINTW */
   91 
   92 
   93 /*
   94  * Most of the logic corresponding to the termcap version is done in InitScreen.
   95  */
   96 void
   97 setup_screen(
   98     void)
   99 {
  100     cmd_line = FALSE;
  101 #   ifdef HAVE_COLOR
  102     bcol(tinrc.col_back);
  103 #   endif /* HAVE_COLOR */
  104     scrollok(stdscr, TRUE);
  105     set_win_size(&cLINES, &cCOLS);
  106 }
  107 
  108 
  109 /*
  110  */
  111 int
  112 InitScreen(
  113     void)
  114 {
  115 #   ifdef NCURSES_VERSION
  116 #       ifdef USE_TRACE
  117 #           ifdef TRACE_CCALLS
  118     trace(TRACE_CALLS|TRACE_CCALLS);
  119 #           else
  120     trace(TRACE_CALLS);
  121 #           endif /* TRACE_CCALLS */
  122 #       endif /* USE_TRACE */
  123 #   endif /* NCURSES_VERSION */
  124     TRACE(("InitScreen"));
  125     initscr();
  126     cCOLS = COLS;
  127     cLINES = LINES - 1;
  128     TRACE(("screen size %d rows by %d cols", LINES, COLS));
  129 /*  set_win_size(&cLINES, &cCOLS); */ /* will be done in setup_screen() */
  130 /*  raw(); */ /* breaks serial terminal using software flow control and cbreak() below does most of the stuff raw() does */
  131     noecho();
  132     cbreak();
  133     cmd_line = FALSE;   /* ...so fcol/bcol will succeed */
  134 
  135     set_keypad_on();
  136 #   ifdef HAVE_COLOR
  137     if (has_colors()) {
  138         start_color();
  139 #       ifdef HAVE_USE_DEFAULT_COLORS
  140         if (use_default_colors() != ERR) {
  141             fcol(default_fcol = -1);
  142             bcol(default_bcol = -1);
  143         }
  144 #       endif /* HAVE_USE_DEFAULT_COLORS */
  145         postinit_colors(MAX(COLORS, MAX_COLOR + 1)); /* postinit_colors(COLORS) would be correct */
  146     } else {
  147         use_color = FALSE;
  148         postinit_colors(MAX_COLOR + 1);
  149     }
  150 
  151 #   endif /* HAVE_COLOR */
  152     set_xclick_on();
  153     return TRUE;
  154 }
  155 
  156 
  157 /*
  158  */
  159 void
  160 InitWin(
  161     void)
  162 {
  163     TRACE(("InitWin"));
  164     Raw(TRUE);
  165     cmd_line = FALSE;
  166     set_keypad_on();
  167 }
  168 
  169 
  170 /*
  171  */
  172 void
  173 EndWin(
  174     void)
  175 {
  176     TRACE(("EndWin(%d)", cmd_line));
  177     if (!cmd_line) {
  178         Raw(FALSE);
  179         endwin();
  180         cmd_line = TRUE;
  181     }
  182 }
  183 
  184 
  185 static int _inraw;
  186 
  187 /*
  188  */
  189 void
  190 Raw(
  191     int state)
  192 {
  193     if (state && !_inraw) {
  194         TRACE(("reset_prog_mode"));
  195         reset_prog_mode();
  196         _inraw = TRUE;
  197     } else if (!state && _inraw) {
  198         TRACE(("reset_shell_mode"));
  199         reset_shell_mode();
  200         _inraw = FALSE;
  201     }
  202 }
  203 
  204 
  205 /*
  206  */
  207 int
  208 RawState(
  209     void)
  210 {
  211     return _inraw;
  212 }
  213 
  214 
  215 /*
  216  */
  217 void
  218 StartInverse(
  219     void)
  220 {
  221     if (tinrc.inverse_okay) {
  222 #   ifdef HAVE_COLOR
  223         if (use_color) {
  224             bcol(tinrc.col_invers_bg);
  225             fcol(tinrc.col_invers_fg);
  226         } else
  227 #   endif /* HAVE_COLOR */
  228         {
  229             attrset(A_REVERSE);
  230         }
  231     }
  232 }
  233 
  234 
  235 #   if 0 /* not used */
  236 static int
  237 isInverse(
  238     void)
  239 {
  240 #       ifdef HAVE_COLOR
  241     if (use_color) {
  242         short pair = PAIR_NUMBER(getattrs(stdscr));
  243         short fg, bg;
  244         pair_content(pair, &fg, &bg);
  245         return (fg == tinrc.col_invers_fg) && (bg == tinrc.col_invers_bg);
  246     }
  247 #       endif /* HAVE_COLOR */
  248 
  249     return (getattrs(stdscr) & A_REVERSE);
  250 }
  251 #   endif /* 0 */
  252 
  253 
  254 #   if 0 /* doesn't work correct with ncurses4.x */
  255 /*
  256  */
  257 void
  258 ToggleInverse(
  259     void)
  260 {
  261     if (isInverse())
  262         EndInverse();
  263     else
  264         StartInverse();
  265 }
  266 #   endif /* 0 */
  267 
  268 
  269 /*
  270  */
  271 void
  272 EndInverse(
  273     void)
  274 {
  275     if (tinrc.inverse_okay && !cmd_line) {
  276 #   ifdef HAVE_COLOR
  277         fcol(tinrc.col_normal);
  278         bcol(tinrc.col_back);
  279 #   endif /* HAVE_COLOR */
  280         attroff(A_REVERSE);
  281     }
  282 }
  283 
  284 
  285 /*
  286  */
  287 void
  288 cursoron(
  289     void)
  290 {
  291     if (!cmd_line)
  292         curs_set(1);
  293 }
  294 
  295 
  296 /*
  297  */
  298 void
  299 cursoroff(
  300     void)
  301 {
  302     if (!cmd_line)
  303         curs_set(0);
  304 }
  305 
  306 
  307 /*
  308  */
  309 void
  310 set_keypad_on(
  311     void)
  312 {
  313     if (!cmd_line)
  314         keypad(stdscr, TRUE);
  315 }
  316 
  317 
  318 /*
  319  */
  320 void
  321 set_keypad_off(
  322     void)
  323 {
  324     if (!cmd_line)
  325         keypad(stdscr, FALSE);
  326 }
  327 
  328 
  329 /*
  330  * Ncurses mouse support is turned on/off when the keypad code is on/off,
  331  * as well as when we enable/disable the mousemask.
  332  */
  333 void
  334 set_xclick_on(
  335     void)
  336 {
  337 #   ifdef NCURSES_MOUSE_VERSION
  338     if (tinrc.use_mouse)
  339         mousemask(
  340             (BUTTON1_CLICKED|BUTTON2_CLICKED|BUTTON3_CLICKED),
  341             (mmask_t *) 0);
  342 #   endif /* NCURSES_MOUSE_VERSION */
  343 }
  344 
  345 
  346 /*
  347  */
  348 void
  349 set_xclick_off(
  350     void)
  351 {
  352 #   ifdef NCURSES_MOUSE_VERSION
  353     (void) mousemask(0, (mmask_t *) 0);
  354 #   endif /* NCURSES_MOUSE_VERSION */
  355 }
  356 
  357 
  358 void
  359 MoveCursor(
  360     int row,
  361     int col)
  362 {
  363     TRACE(("MoveCursor %d,%d", row, col));
  364     if (!cmd_line)
  365         move(row, col);
  366 }
  367 
  368 
  369 /*
  370  * Inverse 'size' chars at (row,col)
  371  */
  372 void
  373 highlight_string(
  374     int row,
  375     int col,
  376     int size)
  377 {
  378     char tmp[LEN];
  379 
  380 #   if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  381     /*
  382      * In a multibyte locale we get byte offsets instead of character
  383      * offsets calculate now the correct starting column
  384      */
  385     if (col > 0) {
  386         wchar_t *wtmp;
  387 
  388         MoveCursor(row, 0);
  389         my_innstr(tmp, cCOLS);
  390         tmp[col] = '\0';
  391         if ((wtmp = char2wchar_t(tmp)) != NULL) {
  392             col = wcswidth(wtmp, wcslen(wtmp) + 1);
  393             free(wtmp);
  394         }
  395     }
  396 #   endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  397 
  398     MoveCursor(row, col);
  399     my_innstr(tmp, size);
  400     tmp[size] = '\0';
  401     StartInverse();
  402     my_fputs(tmp, stdout);
  403     EndInverse();
  404     my_flush();
  405     stow_cursor();
  406 }
  407 
  408 
  409 /*
  410  * Color 'size' chars at (row,col) with 'color' and handle marks
  411  */
  412 void
  413 word_highlight_string(
  414     int row,
  415     int col,
  416     int size,
  417     int color)
  418 {
  419     /*
  420      * Mapping of the tinrc.mono_mark* values to the ncurses attributes
  421      */
  422     int attributes[] = {
  423         A_NORMAL,
  424         A_STANDOUT,
  425         A_UNDERLINE,
  426         A_REVERSE,
  427         A_BLINK,
  428         A_DIM,
  429         A_BOLD
  430     };
  431     char tmp[LEN];
  432     int wsize = size;
  433 #       if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  434     wchar_t *wtmp;
  435 
  436     /*
  437      * In a multibyte locale we get byte offsets instead of character offsets
  438      * calculate now the correct correct starting column
  439      */
  440     if (col > 0) {
  441         MoveCursor(row, 0);
  442         my_innstr(tmp, cCOLS);
  443         tmp[col] = '\0';
  444         if ((wtmp = char2wchar_t(tmp)) != NULL) {
  445             col = wcswidth(wtmp, wcslen(wtmp) + 1);
  446             free(wtmp);
  447         }
  448     }
  449 #       endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  450 
  451     MoveCursor(row, col);
  452     my_innstr(tmp, size);
  453 
  454 #       if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  455     tmp[size] = '\0';
  456     if ((wtmp = char2wchar_t(tmp)) != NULL) {
  457         wsize = wcswidth(wtmp, wcslen(wtmp) + 1);
  458         free(wtmp);
  459     }
  460 #       endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  461 
  462     /* safegurad against bogus regexps */
  463     if ((tmp[0] == '*' && tmp[size - 1] == '*') ||
  464          (tmp[0] == '/' && tmp[size - 1] == '/') ||
  465          (tmp[0] == '_' && tmp[size - 1] == '_') ||
  466          (tmp[0] == '-' && tmp[size - 1] == '-')) {
  467 
  468         switch (tinrc.word_h_display_marks) {
  469             case 0:
  470                 delch();
  471                 mvdelch(row, col + wsize - 2);
  472                 MoveCursor(row, col);
  473                 tmp[0] = tmp[size - 1] = ' ';
  474                 str_trim(tmp);
  475                 break;
  476 
  477             case 2: /* print space */
  478                 MoveCursor(row, col + wsize - 1);
  479                 my_fputs(" ", stdout);
  480                 MoveCursor(row, col);
  481                 my_fputs(" ", stdout);
  482                 tmp[0] = tmp[size - 1] = ' ';
  483                 str_trim(tmp);
  484                 break;
  485 
  486             default: /* print mark (case 1) */
  487                 break;
  488         }
  489     }
  490 #   ifdef HAVE_COLOR
  491     if (use_color)
  492         fcol(color);
  493     else
  494 #   endif /* HAVE_COLOR */
  495         if (color > 0 && color <= MAX_ATTR)
  496             attron(attributes[color]);
  497     my_fputs(tmp, stdout);
  498     my_flush();
  499 #   ifdef HAVE_COLOR
  500     if (use_color)
  501         fcol(tinrc.col_text);
  502     else
  503 #   endif /* HAVE_COLOR */
  504         if (color > 0 && color <= MAX_ATTR)
  505             attroff(attributes[color]);
  506     stow_cursor();
  507 }
  508 
  509 
  510 int
  511 ReadCh(
  512     void)
  513 {
  514     int ch;
  515 
  516     if (cmd_line)
  517         ch = cmdReadCh();
  518     else {
  519 #   if defined(KEY_RESIZE) && defined(USE_CURSES)
  520 again:
  521 #   endif /* KEY_RESIZE && USE_CURSES */
  522         allow_resize(TRUE);
  523 #   if defined(KEY_RESIZE) && defined(USE_CURSES)
  524         if ((ch = getch()) == KEY_RESIZE)
  525             need_resize = cYes;
  526 #       if 0
  527         /*
  528          * disable checking for ERR until all callers of ReadCh() doesn't
  529          * depend on ERR for redrawing
  530          */
  531         if (ch == ERR)
  532             goto again;
  533 #       endif /* 0 */
  534 #   else
  535         ch = getch();
  536 #   endif /* KEY_RESIZE && USE_CURSES */
  537         allow_resize(FALSE);
  538         if (need_resize) {
  539             handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
  540             need_resize = cNo;
  541 #   if defined(KEY_RESIZE) && defined(USE_CURSES)
  542             if (ch == KEY_RESIZE)
  543                 goto again;
  544 #   endif /* KEY_RESIZE && USE_CURSES */
  545 
  546         }
  547         if (ch == KEY_BACKSPACE)
  548             ch = '\010';    /* fix for Ctrl-H - show headers */
  549         else if (ch == ESC || ch >= KEY_MIN) {
  550             ungetch(ch);
  551             ch = ESC;
  552         }
  553     }
  554     TRACE(("ReadCh(%s)", tin_tracechar(ch)));
  555     return ch;
  556 }
  557 
  558 
  559 #   if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  560 wint_t
  561 ReadWch(
  562     void)
  563 {
  564     wint_t wch;
  565     int res;
  566 
  567     if (cmd_line)
  568         wch = cmdReadWch();
  569     else {
  570 again:
  571         allow_resize(TRUE);
  572 #       ifdef HAVE_NCURSESW
  573 #           if defined(KEY_RESIZE) && defined(USE_CURSES)
  574         if ((res = get_wch(&wch)) == KEY_CODE_YES && wch == KEY_RESIZE)
  575             need_resize = cYes;
  576         if (res == ERR)
  577             goto again;
  578 #           else
  579         res = get_wch(&wch);
  580 #           endif /* KEY_RESIZE && USE_CURSES */
  581 #       else
  582         wch = (wint_t) getch();
  583 
  584         if (wch == (wint_t) ERR)
  585             goto again;
  586 
  587         if (wch < KEY_MIN) {
  588             /* read in the multibyte sequence */
  589             char *mbs = my_calloc(1, MB_CUR_MAX + 1);
  590             int i, ch;
  591             wchar_t wc;
  592 
  593             mbs[0] = (char) wch;
  594             nodelay(stdscr, TRUE);
  595             res = mbtowc(&wc, mbs, MB_CUR_MAX);
  596             for (i = 1; i < (int) MB_CUR_MAX && res == -1; i++) {
  597                 if ((res = mbtowc(&wc, mbs, MB_CUR_MAX)) > 0)
  598                     break;
  599                 if ((ch = getch()) != ERR)
  600                     mbs[i] = (char) ch;
  601                 else
  602                     break;
  603             }
  604             nodelay(stdscr, FALSE);
  605 
  606             free(mbs);
  607             if (res == -1)
  608                 return WEOF; /* error */
  609             else {
  610                 res = OK;
  611                 wch = wc;
  612             }
  613         } else {
  614             res = KEY_CODE_YES;
  615 #           if defined(KEY_RESIZE) && defined(USE_CURSES)
  616             if (wch == KEY_RESIZE)
  617                 need_resize = cYes;
  618 #           endif /* KEY_RESIZE && USE_CURSES */
  619         }
  620 #       endif /* HAVE_NCURSESW */
  621         allow_resize(FALSE);
  622         if (need_resize) {
  623             handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
  624             need_resize = cNo;
  625 #       if defined(KEY_RESIZE) && defined(USE_CURSES)
  626             if (wch == KEY_RESIZE)
  627                 goto again;
  628 #       endif /* KEY_RESIZE && USE_CURSES */
  629         }
  630         if (wch == KEY_BACKSPACE)
  631             wch = (wint_t) '\010';  /* fix for Ctrl-H - show headers */
  632         else if (wch == ESC || res == KEY_CODE_YES) {
  633             /* TODO:
  634              * check out why using unget_wch() here causes problems at
  635              * get_arrow_key()
  636              */
  637             /* unget_wch(wch); */
  638             ungetch((int) wch);
  639             wch = ESC;
  640         }
  641     }
  642     return wch;
  643 }
  644 #   endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  645 
  646 
  647 void
  648 my_printf(
  649     const char *fmt,
  650     ...)
  651 {
  652     va_list ap;
  653 
  654     va_start(ap, fmt);
  655     if (cmd_line) {
  656         int flag = _inraw;
  657         if (flag)
  658             Raw(FALSE);
  659         vprintf(fmt, ap);
  660         if (flag)
  661             Raw(TRUE);
  662     } else
  663         vw_printw(stdscr, fmt, ap);
  664 
  665     va_end(ap);
  666 }
  667 
  668 
  669 void
  670 my_fprintf(
  671     FILE *stream,
  672     const char *fmt,
  673     ...)
  674 {
  675     va_list ap;
  676 
  677     va_start(ap, fmt);
  678     TRACE(("my_fprintf(%s)", fmt));
  679     if (cmd_line) {
  680         int flag = _inraw && isatty(fileno(stream));
  681         if (flag)
  682             Raw(FALSE);
  683         vfprintf(stream, fmt, ap);
  684         if (flag)
  685             Raw(TRUE);
  686     } else
  687         vw_printw(stdscr, fmt, ap);
  688 
  689     va_end(ap);
  690 }
  691 
  692 
  693 void
  694 my_fputc(
  695     int ch,
  696     FILE *stream)
  697 {
  698     TRACE(("my_fputc(%s)", tin_tracechar(ch)));
  699     if (cmd_line) {
  700         if (_inraw && ch == '\n')
  701             fputc('\r', stream);
  702         fputc(ch, stream);
  703     } else
  704         addch((unsigned char) ch);
  705 }
  706 
  707 
  708 void
  709 my_fputs(
  710     const char *str,
  711     FILE *stream)
  712 {
  713     TRACE(("my_fputs(%s)", _nc_visbuf(str)));
  714     if (cmd_line) {
  715         if (_inraw) {
  716             while (*str)
  717                 my_fputc(*str++, stream);
  718         } else
  719             fputs(str, stream);
  720     } else {
  721         addstr(str);
  722     }
  723 }
  724 
  725 
  726 #   if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  727 void
  728 my_fputwc(
  729     wint_t wc,
  730     FILE *fp)
  731 {
  732     if (cmd_line) {
  733         if (_inraw && wc == (wint_t) '\n')
  734             fputwc((wint_t) '\r', fp);
  735         fputwc(wc, fp);
  736     } else {
  737 #       ifdef HAVE_NCURSESW
  738         cchar_t cc;
  739         wchar_t wstr[2];
  740 
  741         wstr[0] = (wchar_t) wc;
  742         wstr[1] = (wchar_t) '\0';
  743 
  744         if (setcchar(&cc, wstr, A_NORMAL, 0, NULL) != ERR)
  745             add_wch(&cc);
  746         else
  747             addch('?');
  748 #   else
  749         char *mbs;
  750         int len;
  751 
  752         mbs = my_malloc(MB_CUR_MAX + 1);
  753 
  754         if ((len = wctomb(mbs, wc)) != -1) {
  755             mbs[len] = '\0';
  756             addstr(mbs);
  757         } else
  758             addch('?');
  759 
  760         free(mbs);
  761 #       endif /* HAVE_NCURSESW */
  762     }
  763 }
  764 
  765 
  766 void
  767 my_fputws(
  768     const wchar_t *wstr,
  769     FILE *fp)
  770 {
  771     if (cmd_line) {
  772         if (_inraw) {
  773             while (*wstr)
  774                 my_fputwc(*wstr++, fp);
  775         } else
  776             fputws(wstr, fp);
  777     } else {
  778 #       ifdef HAVE_NCURSESW
  779         addwstr(wstr);
  780 #       else
  781         char *mbs;
  782 
  783         if ((mbs = wchar_t2char(wstr)) != NULL) {
  784             addstr(mbs);
  785             free(mbs);
  786         }
  787 #       endif /* HAVE_NCURSESW */
  788     }
  789 }
  790 #   endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  791 
  792 
  793 void
  794 my_erase(
  795     void)
  796 {
  797     TRACE(("my_erase"));
  798 
  799     if (!cmd_line) {
  800         erase();
  801 
  802         /*
  803          * Curses doesn't actually do an erase() until refresh() is called.
  804          * Ncurses 4.0 (and lower) reset the background color when doing an
  805          * erase(). So the only way to ensure we'll get the same background
  806          * colors is to reset them here.
  807          */
  808         refresh();
  809 #   ifdef HAVE_COLOR
  810         refresh_color();
  811 #   endif /* HAVE_COLOR */
  812     }
  813 }
  814 
  815 
  816 void
  817 my_fflush(
  818     FILE *stream)
  819 {
  820     if (cmd_line)
  821         fflush(stream);
  822     else {
  823         TRACE(("my_fflush"));
  824         refresh();
  825     }
  826 }
  827 
  828 
  829 /*
  830  * Needed if non-curses output has corrupted curses understanding of the screen
  831  */
  832 void
  833 my_retouch(
  834     void)
  835 {
  836     TRACE(("my_retouch"));
  837     if (!cmd_line) {
  838         wrefresh(curscr);
  839 #   ifdef HAVE_COLOR
  840         fcol(tinrc.col_normal);
  841         bcol(tinrc.col_back);
  842 #   endif /* HAVE_COLOR */
  843     }
  844 }
  845 
  846 
  847 /*
  848  * innstr can't read multibyte chars
  849  * we use innwstr (if available) and convert to multibyte chars
  850  */
  851 static int
  852 my_innstr(
  853     char *str,
  854     int n)
  855 {
  856 #   if defined(HAVE_NCURSESW) && defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  857     size_t len = 0;
  858     wchar_t *buffer;
  859 
  860     buffer = my_malloc(sizeof(wchar_t) * (n + 1));
  861 
  862     if (innwstr(buffer, n) != ERR) {
  863         if ((len = wcstombs(str, buffer, 2 * n)) == (size_t) (-1))
  864             len = 0;
  865         str[len] = '\0';
  866     }
  867 
  868     free(buffer);
  869     return len;
  870 #   else
  871     int len = innstr(str, n);
  872     return (len == ERR ? 0 : len);
  873 #   endif /* HAVE_NCURSESW && MULTIBYTE_ABLE && !NO_LOCALE */
  874 }
  875 
  876 
  877 char *
  878 screen_contents(
  879     int row,
  880     int col,
  881     char *buffer)
  882 {
  883     int y, x;
  884     int len = COLS - col;
  885     getyx(stdscr, y, x);
  886     move(row, col);
  887     TRACE(("screen_contents(%d,%d)", row, col));
  888     len = my_innstr(buffer, len);
  889     buffer[len] = '\0';
  890     TRACE(("...screen_contents(%d,%d) %s", y, x, _nc_visbuf(buffer)));
  891     return buffer;
  892 }
  893 
  894 
  895 void
  896 write_line(
  897     int row,
  898     char *buffer)
  899 {
  900     mvaddnstr(row, 0, buffer, -1);
  901 }
  902 
  903 
  904 int
  905 get_arrow_key(
  906     int prech) /* unused */
  907 {
  908 #   ifdef NCURSES_MOUSE_VERSION
  909     MEVENT my_event;
  910 #   endif /* NCURSES_MOUSE_VERSION */
  911     int ch;
  912     int code = KEYMAP_UNKNOWN;
  913 
  914     if (cmd_line)
  915         code = cmd_get_arrow_key(prech);
  916     else {
  917         ch = getch();
  918         switch (ch) {
  919             case KEY_DC:
  920                 code = KEYMAP_DEL;
  921                 break;
  922 
  923             case KEY_IC:
  924                 code = KEYMAP_INS;
  925                 break;
  926 
  927             case KEY_UP:
  928                 code = KEYMAP_UP;
  929                 break;
  930 
  931             case KEY_DOWN:
  932                 code = KEYMAP_DOWN;
  933                 break;
  934 
  935             case KEY_LEFT:
  936                 code = KEYMAP_LEFT;
  937                 break;
  938 
  939             case KEY_RIGHT:
  940                 code = KEYMAP_RIGHT;
  941                 break;
  942 
  943             case KEY_NPAGE:
  944                 code = KEYMAP_PAGE_DOWN;
  945                 break;
  946 
  947             case KEY_PPAGE:
  948                 code = KEYMAP_PAGE_UP;
  949                 break;
  950 
  951             case KEY_HOME:
  952                 code = KEYMAP_HOME;
  953                 break;
  954 
  955             case KEY_END:
  956                 code = KEYMAP_END;
  957                 break;
  958 
  959 #   ifdef NCURSES_MOUSE_VERSION
  960             case KEY_MOUSE:
  961                 if (getmouse(&my_event) != ERR) {
  962                     switch ((int) my_event.bstate) {
  963                         case BUTTON1_CLICKED:
  964                             xmouse = MOUSE_BUTTON_1;
  965                             break;
  966 
  967                         case BUTTON2_CLICKED:
  968                             xmouse = MOUSE_BUTTON_2;
  969                             break;
  970 
  971                         case BUTTON3_CLICKED:
  972                             xmouse = MOUSE_BUTTON_3;
  973                             break;
  974                     }
  975                     xcol = my_event.x;  /* column */
  976                     xrow = my_event.y;  /* row */
  977                     code = KEYMAP_MOUSE;
  978                 }
  979                 break;
  980 #   endif /* NCURSES_MOUSE_VERSION */
  981         }
  982     }
  983     return code;
  984 }
  985 
  986 #else
  987 void my_tcurses(void); /* proto-type */
  988 void my_tcurses(void) { }   /* ANSI C requires non-empty file */
  989 #endif /* USE_CURSES */