"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/src/tcurses.c" (12 Oct 2016, 17487 Bytes) of package /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 "tcurses.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.0_vs_2.4.1.

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