"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.2/src/tcurses.c" (8 Dec 2017, 17571 Bytes) of package /linux/misc/tin-2.4.2.tar.xz:


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

    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   : 2017-10-18
    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-2018 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_calloc(1, MB_CUR_MAX + 1);
  587             int i, ch;
  588             wchar_t wc;
  589 
  590             mbs[0] = (char) wch;
  591             nodelay(stdscr, TRUE);
  592             res = mbtowc(&wc, mbs, MB_CUR_MAX);
  593             for (i = 1; i < (int) MB_CUR_MAX && res == -1; i++) {
  594                 if ((res = mbtowc(&wc, mbs, MB_CUR_MAX)) > 0)
  595                     break;
  596                 if ((ch = getch()) != ERR)
  597                     mbs[i] = (char) ch;
  598                 else
  599                     break;
  600             }
  601             nodelay(stdscr, FALSE);
  602 
  603             free(mbs);
  604             if (res == -1)
  605                 return WEOF; /* error */
  606             else {
  607                 res = OK;
  608                 wch = wc;
  609             }
  610         } else {
  611             res = KEY_CODE_YES;
  612 #           if defined(KEY_RESIZE) && defined(USE_CURSES)
  613             if (wch == KEY_RESIZE)
  614                 need_resize = cYes;
  615 #           endif /* KEY_RESIZE && USE_CURSES */
  616         }
  617 #       endif /* HAVE_NCURSESW */
  618         allow_resize(FALSE);
  619         if (need_resize) {
  620             handle_resize((need_resize == cRedraw) ? TRUE : FALSE);
  621             need_resize = cNo;
  622 #       if defined(KEY_RESIZE) && defined(USE_CURSES)
  623             if (wch == KEY_RESIZE)
  624                 goto again;
  625 #       endif /* KEY_RESIZE && USE_CURSES */
  626         }
  627         if (wch == KEY_BACKSPACE)
  628             wch = (wint_t) '\010';  /* fix for Ctrl-H - show headers */
  629         else if (wch == ESC || res == KEY_CODE_YES) {
  630             /* TODO:
  631              * check out why using unget_wch() here causes problems at
  632              * get_arrow_key()
  633              */
  634             /* unget_wch(wch); */
  635             ungetch((int) wch);
  636             wch = ESC;
  637         }
  638     }
  639     return wch;
  640 }
  641 #   endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  642 
  643 
  644 void
  645 my_printf(
  646     const char *fmt,
  647     ...)
  648 {
  649     va_list ap;
  650 
  651     va_start(ap, fmt);
  652     if (cmd_line) {
  653         int flag = _inraw;
  654         if (flag)
  655             Raw(FALSE);
  656         vprintf(fmt, ap);
  657         if (flag)
  658             Raw(TRUE);
  659     } else
  660         vwprintw(stdscr, fmt, ap);
  661 
  662     va_end(ap);
  663 }
  664 
  665 
  666 void
  667 my_fprintf(
  668     FILE *stream,
  669     const char *fmt,
  670     ...)
  671 {
  672     va_list ap;
  673 
  674     va_start(ap, fmt);
  675     TRACE(("my_fprintf(%s)", fmt));
  676     if (cmd_line) {
  677         int flag = _inraw && isatty(fileno(stream));
  678         if (flag)
  679             Raw(FALSE);
  680         vfprintf(stream, fmt, ap);
  681         if (flag)
  682             Raw(TRUE);
  683     } else
  684         vwprintw(stdscr, fmt, ap);
  685 
  686     va_end(ap);
  687 }
  688 
  689 
  690 void
  691 my_fputc(
  692     int ch,
  693     FILE *stream)
  694 {
  695     TRACE(("my_fputc(%s)", tin_tracechar(ch)));
  696     if (cmd_line) {
  697         if (_inraw && ch == '\n')
  698             fputc('\r', stream);
  699         fputc(ch, stream);
  700     } else
  701         addch((unsigned char) ch);
  702 }
  703 
  704 
  705 void
  706 my_fputs(
  707     const char *str,
  708     FILE *stream)
  709 {
  710     TRACE(("my_fputs(%s)", _nc_visbuf(str)));
  711     if (cmd_line) {
  712         if (_inraw) {
  713             while (*str)
  714                 my_fputc(*str++, stream);
  715         } else
  716             fputs(str, stream);
  717     } else {
  718         addstr(str);
  719     }
  720 }
  721 
  722 
  723 #   if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  724 void
  725 my_fputwc(
  726     wint_t wc,
  727     FILE *fp)
  728 {
  729     if (cmd_line) {
  730         if (_inraw && wc == (wint_t) '\n')
  731             fputwc((wint_t) '\r', fp);
  732         fputwc(wc, fp);
  733     } else {
  734 #       ifdef HAVE_NCURSESW
  735         cchar_t cc;
  736         wchar_t wstr[2];
  737 
  738         wstr[0] = (wchar_t) wc;
  739         wstr[1] = (wchar_t) '\0';
  740 
  741         if (setcchar(&cc, wstr, A_NORMAL, 0, NULL) != ERR)
  742             add_wch(&cc);
  743         else
  744             addch('?');
  745 #   else
  746         char *mbs;
  747         int len;
  748 
  749         mbs = my_malloc(MB_CUR_MAX + 1);
  750 
  751         if ((len = wctomb(mbs, wc)) != -1) {
  752             mbs[len] = '\0';
  753             addstr(mbs);
  754         } else
  755             addch('?');
  756 
  757         free(mbs);
  758 #       endif /* HAVE_NCURSESW */
  759     }
  760 }
  761 
  762 
  763 void
  764 my_fputws(
  765     const wchar_t *wstr,
  766     FILE *fp)
  767 {
  768     if (cmd_line) {
  769         if (_inraw) {
  770             while (*wstr)
  771                 my_fputwc(*wstr++, fp);
  772         } else
  773             fputws(wstr, fp);
  774     } else {
  775 #       ifdef HAVE_NCURSESW
  776         addwstr(wstr);
  777 #       else
  778         char *mbs;
  779 
  780         if ((mbs = wchar_t2char(wstr)) != NULL) {
  781             addstr(mbs);
  782             free(mbs);
  783         }
  784 #       endif /* HAVE_NCURSESW */
  785     }
  786 }
  787 #   endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  788 
  789 
  790 void
  791 my_erase(
  792     void)
  793 {
  794     TRACE(("my_erase"));
  795 
  796     if (!cmd_line) {
  797         erase();
  798 
  799         /*
  800          * Curses doesn't actually do an erase() until refresh() is called.
  801          * Ncurses 4.0 (and lower) reset the background color when doing an
  802          * erase(). So the only way to ensure we'll get the same background
  803          * colors is to reset them here.
  804          */
  805         refresh();
  806 #   ifdef HAVE_COLOR
  807         refresh_color();
  808 #   endif /* HAVE_COLOR */
  809     }
  810 }
  811 
  812 
  813 void
  814 my_fflush(
  815     FILE *stream)
  816 {
  817     if (cmd_line)
  818         fflush(stream);
  819     else {
  820         TRACE(("my_fflush"));
  821         refresh();
  822     }
  823 }
  824 
  825 
  826 /*
  827  * Needed if non-curses output has corrupted curses understanding of the screen
  828  */
  829 void
  830 my_retouch(
  831     void)
  832 {
  833     TRACE(("my_retouch"));
  834     if (!cmd_line) {
  835         wrefresh(curscr);
  836 #   ifdef HAVE_COLOR
  837         fcol(tinrc.col_normal);
  838         bcol(tinrc.col_back);
  839 #   endif /* HAVE_COLOR */
  840     }
  841 }
  842 
  843 
  844 /*
  845  * innstr can't read multibyte chars
  846  * we use innwstr (if avaible) and convert to multibyte chars
  847  */
  848 static int
  849 my_innstr(
  850     char *str,
  851     int n)
  852 {
  853 #   if defined(HAVE_NCURSESW) && defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  854     size_t len = 0;
  855     wchar_t *buffer;
  856 
  857     buffer = my_malloc(sizeof(wchar_t) * (n + 1));
  858 
  859     if (innwstr(buffer, n) != ERR) {
  860         if ((len = wcstombs(str, buffer, 2 * n)) == (size_t) (-1))
  861             len = 0;
  862         str[len] = '\0';
  863     }
  864 
  865     free(buffer);
  866     return len;
  867 #   else
  868     int len = innstr(str, n);
  869     return (len == ERR ? 0 : len);
  870 #   endif /* HAVE_NCURSESW && MULTIBYTE_ABLE && !NO_LOCALE */
  871 }
  872 
  873 
  874 char *
  875 screen_contents(
  876     int row,
  877     int col,
  878     char *buffer)
  879 {
  880     int y, x;
  881     int len = COLS - col;
  882     getyx(stdscr, y, x);
  883     move(row, col);
  884     TRACE(("screen_contents(%d,%d)", row, col));
  885     len = my_innstr(buffer, len);
  886     buffer[len] = '\0';
  887     TRACE(("...screen_contents(%d,%d) %s", y, x, _nc_visbuf(buffer)));
  888     return buffer;
  889 }
  890 
  891 
  892 void
  893 write_line(
  894     int row,
  895     char *buffer)
  896 {
  897     mvaddnstr(row, 0, buffer, -1);
  898 }
  899 
  900 
  901 int
  902 get_arrow_key(
  903     int prech) /* unused */
  904 {
  905 #   ifdef NCURSES_MOUSE_VERSION
  906     MEVENT my_event;
  907 #   endif /* NCURSES_MOUSE_VERSION */
  908     int ch;
  909     int code = KEYMAP_UNKNOWN;
  910 
  911     if (cmd_line)
  912         code = cmd_get_arrow_key(prech);
  913     else {
  914         ch = getch();
  915         switch (ch) {
  916             case KEY_DC:
  917                 code = KEYMAP_DEL;
  918                 break;
  919 
  920             case KEY_IC:
  921                 code = KEYMAP_INS;
  922                 break;
  923 
  924             case KEY_UP:
  925                 code = KEYMAP_UP;
  926                 break;
  927 
  928             case KEY_DOWN:
  929                 code = KEYMAP_DOWN;
  930                 break;
  931 
  932             case KEY_LEFT:
  933                 code = KEYMAP_LEFT;
  934                 break;
  935 
  936             case KEY_RIGHT:
  937                 code = KEYMAP_RIGHT;
  938                 break;
  939 
  940             case KEY_NPAGE:
  941                 code = KEYMAP_PAGE_DOWN;
  942                 break;
  943 
  944             case KEY_PPAGE:
  945                 code = KEYMAP_PAGE_UP;
  946                 break;
  947 
  948             case KEY_HOME:
  949                 code = KEYMAP_HOME;
  950                 break;
  951 
  952             case KEY_END:
  953                 code = KEYMAP_END;
  954                 break;
  955 
  956 #   ifdef NCURSES_MOUSE_VERSION
  957             case KEY_MOUSE:
  958                 if (getmouse(&my_event) != ERR) {
  959                     switch ((int) my_event.bstate) {
  960                         case BUTTON1_CLICKED:
  961                             xmouse = MOUSE_BUTTON_1;
  962                             break;
  963 
  964                         case BUTTON2_CLICKED:
  965                             xmouse = MOUSE_BUTTON_2;
  966                             break;
  967 
  968                         case BUTTON3_CLICKED:
  969                             xmouse = MOUSE_BUTTON_3;
  970                             break;
  971                     }
  972                     xcol = my_event.x;  /* column */
  973                     xrow = my_event.y;  /* row */
  974                     code = KEYMAP_MOUSE;
  975                 }
  976                 break;
  977 #   endif /* NCURSES_MOUSE_VERSION */
  978         }
  979     }
  980     return code;
  981 }
  982 
  983 #else
  984 void my_tcurses(void); /* proto-type */
  985 void my_tcurses(void) { }   /* ANSI C requires non-empty file */
  986 #endif /* USE_CURSES */