summaryrefslogtreecommitdiff
path: root/pico/osdep/terminal.c
diff options
context:
space:
mode:
Diffstat (limited to 'pico/osdep/terminal.c')
-rw-r--r--pico/osdep/terminal.c1762
1 files changed, 1762 insertions, 0 deletions
diff --git a/pico/osdep/terminal.c b/pico/osdep/terminal.c
new file mode 100644
index 00000000..72206c01
--- /dev/null
+++ b/pico/osdep/terminal.c
@@ -0,0 +1,1762 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: terminal.c 921 2008-01-31 02:09:25Z hubert@u.washington.edu $";
+#endif
+
+/*
+ * ========================================================================
+ * Copyright 2006-2008 University of Washington
+ * Copyright 2013 Eduardo Chappa
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ========================================================================
+ *
+ * Program: Display routines
+ */
+
+#include <system.h>
+#include <general.h>
+
+
+#include "../estruct.h"
+#include "../keydefs.h"
+#include "../pico.h"
+#include "../mode.h"
+
+#include "raw.h"
+#include "color.h"
+#include "tty.h"
+#include "terminal.h"
+#include "getkey.h"
+
+#ifndef _WINDOWS
+extern long gmode;
+
+
+/*
+ * Useful Defaults
+ */
+#define MARGIN 8 /* size of minimim margin and */
+#define MROW 2 /* rows in menu */
+
+
+/* any special properties of the current terminal */
+unsigned term_capabilities = (TT_EOLEXIST | TT_SCROLLEXIST | TT_INSCHAR | TT_DELCHAR);
+
+
+/*
+ *
+ */
+unsigned
+tthascap(void)
+{
+ return(term_capabilities);
+}
+
+
+#if HAS_TERMINFO
+
+/*
+ * terminfo-based terminal i/o and control routines
+ */
+
+
+/* internal prototypes */
+static int tinfomove(int, int);
+static int tinfoeeol(void);
+static int tinfoeeop(void);
+static int tinfobeep(void);
+static int tinforev(int);
+static int tinfoopen(void);
+static int tinfoterminalinfo(int);
+static int tinfoclose(void);
+static void setup_dflt_esc_seq(void);
+static void tinfoinsert(UCS);
+static void tinfodelete(void);
+
+extern int tput();
+extern int tputs(char *, int, int (*)(int));
+extern char *tgoto(char *, int, int);
+extern char *tigetstr ();
+extern int setupterm(char *, int, int *);
+extern int tigetnum(char *);
+extern int tigetflag(char *);
+
+/**
+ ** Note: The tgoto calls should really be replaced by tparm calls for
+ ** modern terminfo. tgoto(s, x, y) == tparm(s, y, x).
+ **/
+
+int _tlines, _tcolumns;
+char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
+ *_setinverse, *_clearinverse,
+ *_setunderline, *_clearunderline,
+ *_setbold, *_clearallattr, /* there is no clear only bold! */
+ *_cleartoeoln, *_cleartoeos,
+ *_deleteline, /* delete line */
+ *_insertline, /* insert line */
+ *_scrollregion, /* define a scrolling region, vt100 */
+ *_insertchar, /* insert character, preferable to : */
+ *_startinsert, /* set insert mode and, */
+ *_endinsert, /* end insert mode */
+ *_deletechar, /* delete character */
+ *_startdelete, /* set delete mode and, */
+ *_enddelete, /* end delete mode */
+ *_scrolldown, /* scroll down */
+ *_scrollup, /* scroll up */
+ *_termcap_init, /* string to start termcap */
+ *_termcap_end, /* string to end termcap */
+ *_op, *_oc, *_setaf, *_setab, *_setf, *_setb, *_scp;
+int _colors, _pairs, _bce;
+char term_name[40];
+
+TERM term = {
+ NROW-1,
+ NCOL,
+ MARGIN,
+ MROW,
+ tinfoopen,
+ tinfoterminalinfo,
+ tinfoclose,
+ ttgetc,
+ ttputc,
+ ttflush,
+ tinfomove,
+ tinfoeeol,
+ tinfoeeop,
+ tinfobeep,
+ tinforev
+};
+
+
+/*
+ * Add default keypad sequences to the trie.
+ */
+static void
+setup_dflt_esc_seq(void)
+{
+ /*
+ * this is sort of a hack [no kidding], but it allows us to use
+ * the function keys on pc's running telnet
+ */
+
+ /*
+ * UW-NDC/UCS vt10[02] application mode.
+ */
+ kpinsert("\033OP", F1, 1);
+ kpinsert("\033OQ", F2, 1);
+ kpinsert("\033OR", F3, 1);
+ kpinsert("\033OS", F4, 1);
+ kpinsert("\033Op", F5, 1);
+ kpinsert("\033Oq", F6, 1);
+ kpinsert("\033Or", F7, 1);
+ kpinsert("\033Os", F8, 1);
+ kpinsert("\033Ot", F9, 1);
+ kpinsert("\033Ou", F10, 1);
+ kpinsert("\033Ov", F11, 1);
+ kpinsert("\033Ow", F12, 1);
+
+ /*
+ * DEC vt100, ANSI and cursor key mode.
+ */
+ kpinsert("\033OA", KEY_UP, 1);
+ kpinsert("\033OB", KEY_DOWN, 1);
+ kpinsert("\033OC", KEY_RIGHT, 1);
+ kpinsert("\033OD", KEY_LEFT, 1);
+
+ /*
+ * special keypad functions
+ */
+ kpinsert("\033[4J", KEY_PGUP, 1);
+ kpinsert("\033[3J", KEY_PGDN, 1);
+ kpinsert("\033[2J", KEY_HOME, 1);
+ kpinsert("\033[N", KEY_END, 1);
+
+ /*
+ * vt220?
+ */
+ kpinsert("\033[5~", KEY_PGUP, 1);
+ kpinsert("\033[6~", KEY_PGDN, 1);
+ kpinsert("\033[1~", KEY_HOME, 1);
+ kpinsert("\033[4~", KEY_END, 1);
+
+ /*
+ * konsole, XTerm (XFree 4.x.x) keyboard setting
+ */
+ kpinsert("\033[H", KEY_HOME, 1);
+ kpinsert("\033[F", KEY_END, 1);
+
+ /*
+ * gnome-terminal 2.6.0, don't know why it
+ * changed from 2.2.1
+ */
+ kpinsert("\033OH", KEY_HOME, 1);
+ kpinsert("\033OF", KEY_END, 1);
+
+ /*
+ * "\033[2~" was common for KEY_HOME in a quick survey
+ * of terminals (though typically the Insert key).
+ * Teraterm 2.33 sends the following escape sequences,
+ * which is quite incompatible with everything
+ * else:
+ * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
+ * PgDn: "\033[6~"
+ * The best thing to do would be to fix TeraTerm
+ * keymappings or to tweak terminfo.
+ */
+
+ /*
+ * ANSI mode.
+ */
+ kpinsert("\033[=a", F1, 1);
+ kpinsert("\033[=b", F2, 1);
+ kpinsert("\033[=c", F3, 1);
+ kpinsert("\033[=d", F4, 1);
+ kpinsert("\033[=e", F5, 1);
+ kpinsert("\033[=f", F6, 1);
+ kpinsert("\033[=g", F7, 1);
+ kpinsert("\033[=h", F8, 1);
+ kpinsert("\033[=i", F9, 1);
+ kpinsert("\033[=j", F10, 1);
+ kpinsert("\033[=k", F11, 1);
+ kpinsert("\033[=l", F12, 1);
+
+ /*
+ * DEC vt100, ANSI and cursor key mode reset.
+ */
+ kpinsert("\033[A", KEY_UP, 1);
+ kpinsert("\033[B", KEY_DOWN, 1);
+ kpinsert("\033[C", KEY_RIGHT, 1);
+ kpinsert("\033[D", KEY_LEFT, 1);
+
+ /*
+ * DEC vt52 mode.
+ */
+ kpinsert("\033A", KEY_UP, 1);
+ kpinsert("\033B", KEY_DOWN, 1);
+ kpinsert("\033C", KEY_RIGHT, 1);
+ kpinsert("\033D", KEY_LEFT, 1);
+
+ /*
+ * DEC vt52 application keys, and some Zenith 19.
+ */
+ kpinsert("\033?r", KEY_DOWN, 1);
+ kpinsert("\033?t", KEY_LEFT, 1);
+ kpinsert("\033?v", KEY_RIGHT, 1);
+ kpinsert("\033?x", KEY_UP, 1);
+
+ /*
+ * Some Ctrl-Arrow keys
+ */
+ kpinsert("\033[5A", CTRL_KEY_UP, 1);
+ kpinsert("\033[5B", CTRL_KEY_DOWN, 1);
+ kpinsert("\033[5C", CTRL_KEY_RIGHT, 1);
+ kpinsert("\033[5D", CTRL_KEY_LEFT, 1);
+
+ kpinsert("\033[1;5A", CTRL_KEY_UP, 1);
+ kpinsert("\033[1;5B", CTRL_KEY_DOWN, 1);
+ kpinsert("\033[1;5C", CTRL_KEY_RIGHT, 1);
+ kpinsert("\033[1;5D", CTRL_KEY_LEFT, 1);
+
+ /*
+ * Map some shift+up/down/left/right to their shiftless counterparts
+ */
+ kpinsert("\033[1;2A", KEY_UP, 1);
+ kpinsert("\033[1;2B", KEY_DOWN, 1);
+ kpinsert("\033[1;2C", KEY_RIGHT, 1);
+ kpinsert("\033[1;2D", KEY_LEFT, 1);
+ kpinsert("\033[a", KEY_UP, 1);
+ kpinsert("\033[b", KEY_DOWN, 1);
+ kpinsert("\033[c", KEY_RIGHT, 1);
+ kpinsert("\033[d", KEY_LEFT, 1);
+
+ /*
+ * Sun Console sequences.
+ */
+ kpinsert("\033[1", KEY_SWALLOW_Z, 1);
+ kpinsert("\033[215", KEY_SWAL_UP, 1);
+ kpinsert("\033[217", KEY_SWAL_LEFT, 1);
+ kpinsert("\033[219", KEY_SWAL_RIGHT, 1);
+ kpinsert("\033[221", KEY_SWAL_DOWN, 1);
+
+ /*
+ * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
+ */
+ kpinsert("\033_", KEY_KERMIT, 1);
+
+ /*
+ * Fake a control character.
+ */
+ kpinsert("\033\033", KEY_DOUBLE_ESC, 1);
+}
+
+
+static int
+tinfoterminalinfo(int termcap_wins)
+{
+ char *_ku, *_kd, *_kl, *_kr,
+ *_kppu, *_kppd, *_kphome, *_kpend, *_kpdel,
+ *_kf1, *_kf2, *_kf3, *_kf4, *_kf5, *_kf6,
+ *_kf7, *_kf8, *_kf9, *_kf10, *_kf11, *_kf12;
+ char *ttnm;
+
+ if (Pmaster) {
+ /*
+ * setupterm() automatically retrieves the value
+ * of the TERM variable.
+ */
+ int err;
+ ttnm = getenv("TERM");
+ if(!ttnm)
+ return(-1);
+
+ strncpy(term_name, ttnm, sizeof(term_name));
+ term_name[sizeof(term_name)-1] = '\0';
+ setupterm ((char *) 0, 1, &err);
+ if (err != 1) return(err-2);
+ }
+ else {
+ /*
+ * setupterm() issues a message and exits, if the
+ * terminfo data base is gone or the term type is
+ * unknown, if arg2 is 0.
+ */
+ setupterm ((char *) 0, 1, (int *) 0);
+ }
+
+ _clearscreen = tigetstr("clear");
+ _moveto = tigetstr("cup");
+ _up = tigetstr("cuu1");
+ _down = tigetstr("cud1");
+ _right = tigetstr("cuf1");
+ _left = tigetstr("cub1");
+ _setinverse = tigetstr("smso");
+ _clearinverse = tigetstr("rmso");
+ _setunderline = tigetstr("smul");
+ _clearunderline = tigetstr("rmul");
+ _setbold = tigetstr("bold");
+ _clearallattr = tigetstr("sgr0");
+ _cleartoeoln = tigetstr("el");
+ _cleartoeos = tigetstr("ed");
+ _deletechar = tigetstr("dch1");
+ _insertchar = tigetstr("ich1");
+ _startinsert = tigetstr("smir");
+ _endinsert = tigetstr("rmir");
+ _deleteline = tigetstr("dl1");
+ _insertline = tigetstr("il1");
+ _scrollregion = tigetstr("csr");
+ _scrolldown = tigetstr("ind");
+ _scrollup = tigetstr("ri");
+ _termcap_init = tigetstr("smcup");
+ _termcap_end = tigetstr("rmcup");
+ _startdelete = tigetstr("smdc");
+ _enddelete = tigetstr("rmdc");
+ _ku = tigetstr("kcuu1");
+ _kd = tigetstr("kcud1");
+ _kl = tigetstr("kcub1");
+ _kr = tigetstr("kcuf1");
+ _kppu = tigetstr("kpp");
+ _kppd = tigetstr("knp");
+ _kphome = tigetstr("khome");
+ _kpend = tigetstr("kend");
+ _kpdel = tigetstr("kdch1");
+ _kf1 = tigetstr("kf1");
+ _kf2 = tigetstr("kf2");
+ _kf3 = tigetstr("kf3");
+ _kf4 = tigetstr("kf4");
+ _kf5 = tigetstr("kf5");
+ _kf6 = tigetstr("kf6");
+ _kf7 = tigetstr("kf7");
+ _kf8 = tigetstr("kf8");
+ _kf9 = tigetstr("kf9");
+ _kf10 = tigetstr("kf10");
+ _kf11 = tigetstr("kf11");
+ _kf12 = tigetstr("kf12");
+
+ _colors = tigetnum("colors");
+ _pairs = tigetnum("pairs");
+ _setaf = tigetstr("setaf");
+ _setab = tigetstr("setab");
+ _setf = tigetstr("setf");
+ _setb = tigetstr("setb");
+ _scp = tigetstr("scp");
+ _op = tigetstr("op");
+ _oc = tigetstr("oc");
+ _bce = tigetflag("bce");
+
+ _tlines = tigetnum("lines");
+ if(_tlines == -1){
+ char *er;
+ int rr;
+
+ /* tigetnum failed, try $LINES */
+ er = getenv("LINES");
+ if(er && (rr = atoi(er)) > 0)
+ _tlines = rr;
+ }
+
+ _tcolumns = tigetnum("cols");
+ if(_tcolumns == -1){
+ char *ec;
+ int cc;
+
+ /* tigetnum failed, try $COLUMNS */
+ ec = getenv("COLUMNS");
+ if(ec && (cc = atoi(ec)) > 0)
+ _tcolumns = cc;
+ }
+
+ /*
+ * Add default keypad sequences to the trie.
+ * Since these come first, they will override any conflicting termcap
+ * or terminfo escape sequences defined below. An escape sequence is
+ * considered conflicting if one is a prefix of the other.
+ * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
+ * escape sequences that don't work, because they conflict with default
+ * sequences defined here.
+ */
+ if(!termcap_wins)
+ setup_dflt_esc_seq();
+
+ /*
+ * add termcap/info escape sequences to the trie...
+ */
+
+ if(_ku != NULL && _kd != NULL && _kl != NULL && _kr != NULL){
+ kpinsert(_ku, KEY_UP, termcap_wins);
+ kpinsert(_kd, KEY_DOWN, termcap_wins);
+ kpinsert(_kl, KEY_LEFT, termcap_wins);
+ kpinsert(_kr, KEY_RIGHT, termcap_wins);
+ }
+
+ if(_kppu != NULL && _kppd != NULL){
+ kpinsert(_kppu, KEY_PGUP, termcap_wins);
+ kpinsert(_kppd, KEY_PGDN, termcap_wins);
+ }
+
+ kpinsert(_kphome, KEY_HOME, termcap_wins);
+ kpinsert(_kpend, KEY_END, termcap_wins);
+ kpinsert(_kpdel, KEY_DEL, termcap_wins);
+
+ kpinsert(_kf1, F1, termcap_wins);
+ kpinsert(_kf2, F2, termcap_wins);
+ kpinsert(_kf3, F3, termcap_wins);
+ kpinsert(_kf4, F4, termcap_wins);
+ kpinsert(_kf5, F5, termcap_wins);
+ kpinsert(_kf6, F6, termcap_wins);
+ kpinsert(_kf7, F7, termcap_wins);
+ kpinsert(_kf8, F8, termcap_wins);
+ kpinsert(_kf9, F9, termcap_wins);
+ kpinsert(_kf10, F10, termcap_wins);
+ kpinsert(_kf11, F11, termcap_wins);
+ kpinsert(_kf12, F12, termcap_wins);
+
+ /*
+ * Add default keypad sequences to the trie.
+ * Since these come after the termcap/terminfo escape sequences above,
+ * the termcap/info sequences will override any conflicting default
+ * escape sequences defined here.
+ * So, with TERMCAP_WINS, some of the default sequences will be missing.
+ * This means that you'd better get all of your termcap/terminfo entries
+ * correct if you define TERMCAP_WINS.
+ */
+ if(termcap_wins)
+ setup_dflt_esc_seq();
+
+ if(Pmaster)
+ return(0);
+ else
+ return(TRUE);
+}
+
+static int
+tinfoopen(void)
+{
+ int row, col;
+
+ /*
+ * determine the terminal's communication speed and decide
+ * if we need to do optimization ...
+ */
+ if(ttisslow())
+ term_capabilities |= TT_OPTIMIZE;
+
+ col = _tcolumns;
+ row = _tlines;
+ if(row >= 0)
+ row--;
+
+ ttgetwinsz(&row, &col);
+ term.t_nrow = (short) row;
+ term.t_ncol = (short) col;
+
+ if(_cleartoeoln != NULL) /* able to use clear to EOL? */
+ term_capabilities |= TT_EOLEXIST;
+ else
+ term_capabilities &= ~TT_EOLEXIST;
+
+ if(_setinverse != NULL)
+ term_capabilities |= TT_REVEXIST;
+ else
+ term_capabilities &= ~TT_REVEXIST;
+
+ if(_deletechar == NULL && (_startdelete == NULL || _enddelete == NULL))
+ term_capabilities &= ~TT_DELCHAR;
+
+ if(_insertchar == NULL && (_startinsert == NULL || _endinsert == NULL))
+ term_capabilities &= ~TT_INSCHAR;
+
+ if((_scrollregion == NULL || _scrolldown == NULL || _scrollup == NULL)
+ && (_deleteline == NULL || _insertline == NULL))
+ term_capabilities &= ~TT_SCROLLEXIST;
+
+ if(_clearscreen == NULL || _moveto == NULL || _up == NULL){
+ if(Pmaster == NULL){
+ puts("Incomplete terminfo entry\n");
+ exit(1);
+ }
+ }
+
+ ttopen();
+
+ if(_termcap_init && !Pmaster) {
+ putpad(_termcap_init); /* any init terminfo requires */
+ if (_scrollregion)
+ putpad(tgoto(_scrollregion, term.t_nrow, 0)) ;
+ }
+
+ /*
+ * Initialize UW-modified NCSA telnet to use its functionkeys
+ */
+ if((gmode & MDFKEY) && Pmaster == NULL)
+ puts("\033[99h");
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tinfoclose(void)
+{
+ if(!Pmaster){
+ if(gmode&MDFKEY)
+ puts("\033[99l"); /* reset UW-NCSA telnet keys */
+
+ if(_termcap_end) /* any clean up terminfo requires */
+ putpad(_termcap_end);
+ }
+
+ ttclose();
+
+ /* return ignored */
+ return(0);
+}
+
+
+/*
+ * tinfoinsert - insert a character at the current character position.
+ * _insertchar takes precedence.
+ */
+static void
+tinfoinsert(UCS ch)
+{
+ if(_insertchar != NULL){
+ putpad(_insertchar);
+ ttputc(ch);
+ }
+ else{
+ putpad(_startinsert);
+ ttputc(ch);
+ putpad(_endinsert);
+ }
+}
+
+
+/*
+ * tinfodelete - delete a character at the current character position.
+ */
+static void
+tinfodelete(void)
+{
+ if(_startdelete == NULL && _enddelete == NULL)
+ putpad(_deletechar);
+ else{
+ putpad(_startdelete);
+ putpad(_deletechar);
+ putpad(_enddelete);
+ }
+}
+
+
+/*
+ * o_scrolldown() - open a line at the given row position.
+ * use either region scrolling or deleteline/insertline
+ * to open a new line.
+ */
+int
+o_scrolldown(int row, int n)
+{
+ register int i;
+
+ if(_scrollregion != NULL){
+ putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
+ tinfomove(row, 0);
+ for(i = 0; i < n; i++)
+ putpad((_scrollup != NULL && *_scrollup != '\0') ? _scrollup : "\n" );
+ putpad(tgoto(_scrollregion, term.t_nrow, 0));
+ tinfomove(row, 0);
+ }
+ else{
+ /*
+ * this code causes a jiggly motion of the keymenu when scrolling
+ */
+ for(i = 0; i < n; i++){
+ tinfomove(term.t_nrow - (term.t_mrow+1), 0);
+ putpad(_deleteline);
+ tinfomove(row, 0);
+ putpad(_insertline);
+ }
+#ifdef NOWIGGLYLINES
+ /*
+ * this code causes a sweeping motion up and down the display
+ */
+ tinfomove(term.t_nrow - term.t_mrow - n, 0);
+ for(i = 0; i < n; i++)
+ putpad(_deleteline);
+ tinfomove(row, 0);
+ for(i = 0; i < n; i++)
+ putpad(_insertline);
+#endif
+ }
+
+ /* return ignored */
+ return(0);
+}
+
+
+/*
+ * o_scrollup() - open a line at the given row position.
+ * use either region scrolling or deleteline/insertline
+ * to open a new line.
+ */
+int
+o_scrollup(int row, int n)
+{
+ register int i;
+
+ if(_scrollregion != NULL){
+ putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
+ /* setting scrolling region moves cursor to home */
+ tinfomove(term.t_nrow-(term.t_mrow+1), 0);
+ for(i = 0;i < n; i++)
+ putpad((_scrolldown == NULL || _scrolldown[0] == '\0') ? "\n"
+ : _scrolldown);
+ putpad(tgoto(_scrollregion, term.t_nrow, 0));
+ tinfomove(2, 0);
+ }
+ else{
+ for(i = 0; i < n; i++){
+ tinfomove(row, 0);
+ putpad(_deleteline);
+ tinfomove(term.t_nrow - (term.t_mrow+1), 0);
+ putpad(_insertline);
+ }
+#ifdef NOWIGGLYLINES
+ /* see note above */
+ tinfomove(row, 0);
+ for(i = 0; i < n; i++)
+ putpad(_deleteline);
+ tinfomove(term.t_nrow - term.t_mrow - n, 0);
+ for(i = 0;i < n; i++)
+ putpad(_insertline);
+#endif
+ }
+
+ /* return ignored */
+ return(0);
+}
+
+
+
+/*
+ * o_insert - use terminfo to optimized character insert
+ * returns: true if it optimized output, false otherwise
+ */
+int
+o_insert(UCS c)
+{
+ if(term_capabilities & TT_INSCHAR){
+ tinfoinsert(c);
+ return(1); /* no problems! */
+ }
+
+ return(0); /* can't do it. */
+}
+
+
+/*
+ * o_delete - use terminfo to optimized character insert
+ * returns true if it optimized output, false otherwise
+ */
+int
+o_delete(void)
+{
+ if(term_capabilities & TT_DELCHAR){
+ tinfodelete();
+ return(1); /* deleted, no problem! */
+ }
+
+ return(0); /* no dice. */
+}
+
+
+static int
+tinfomove(int row, int col)
+{
+ putpad(tgoto(_moveto, col, row));
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tinfoeeol(void)
+{
+ int c, starting_col, starting_line;
+ char *last_bg_color;
+
+ /*
+ * If the terminal doesn't have back color erase, then we have to
+ * erase manually to preserve the background color.
+ */
+ if(pico_usingcolor() && (!_bce || !_cleartoeoln)){
+ extern int ttcol, ttrow;
+
+ starting_col = ttcol;
+ starting_line = ttrow;
+ last_bg_color = pico_get_last_bg_color();
+ pico_set_nbg_color();
+ for(c = ttcol; c < term.t_ncol; c++)
+ ttputc(' ');
+
+ tinfomove(starting_line, starting_col);
+ if(last_bg_color){
+ pico_set_bg_color(last_bg_color);
+ free(last_bg_color);
+ }
+ }
+ else if(_cleartoeoln)
+ putpad(_cleartoeoln);
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tinfoeeop(void)
+{
+ int i, starting_col, starting_row;
+
+ /*
+ * If the terminal doesn't have back color erase, then we have to
+ * erase manually to preserve the background color.
+ */
+ if(pico_usingcolor() && (!_bce || !_cleartoeos)){
+ extern int ttcol, ttrow;
+
+ starting_col = ttcol;
+ starting_row = ttrow;
+ tinfoeeol(); /* rest of this line */
+ for(i = ttrow+1; i <= term.t_nrow; i++){ /* the remaining lines */
+ tinfomove(i, 0);
+ tinfoeeol();
+ }
+
+ tinfomove(starting_row, starting_col);
+ }
+ else if(_cleartoeos)
+ putpad(_cleartoeos);
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tinforev(int state) /* change reverse video status */
+{ /* FALSE = normal video, TRUE = rev video */
+ if(state)
+ StartInverse();
+ else
+ EndInverse();
+
+ return(1);
+}
+
+
+static int
+tinfobeep(void)
+{
+ ttputc(BELL);
+
+ /* return ignored */
+ return(0);
+}
+
+
+void
+putpad(char *str)
+{
+ tputs(str, 1, putchar);
+}
+
+#elif HAS_TERMCAP
+
+/*
+ * termcap-based terminal i/o and control routines
+ */
+
+
+/* internal prototypes */
+static int tcapmove(int, int);
+static int tcapeeol(void);
+static int tcapeeop(void);
+static int tcapbeep(void);
+static int tcaprev(int);
+static int tcapopen(void);
+static int tcapterminalinfo(int);
+static int tcapclose(void);
+static void setup_dflt_esc_seq(void);
+static void tcapinsert(UCS);
+static void tcapdelete(void);
+
+extern int tput();
+extern char *tgoto(char *, int, int);
+
+/*
+ * This number used to be 315. No doubt there was a reason for that but we
+ * don't know what it was. It's a bit of a hassle to make it dynamic, and most
+ * modern systems seem to be using terminfo, so we'll just change it to 800.
+ * We weren't stopping on overflow before, so we'll do that, too.
+ */
+#define TCAPSLEN 800
+char tcapbuf[TCAPSLEN];
+int _tlines, _tcolumns;
+char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
+ *_setinverse, *_clearinverse,
+ *_setunderline, *_clearunderline,
+ *_setbold, *_clearallattr, /* there is no clear only bold! */
+ *_cleartoeoln, *_cleartoeos,
+ *_deleteline, /* delete line */
+ *_insertline, /* insert line */
+ *_scrollregion, /* define a scrolling region, vt100 */
+ *_insertchar, /* insert character, preferable to : */
+ *_startinsert, /* set insert mode and, */
+ *_endinsert, /* end insert mode */
+ *_deletechar, /* delete character */
+ *_startdelete, /* set delete mode and, */
+ *_enddelete, /* end delete mode */
+ *_scrolldown, /* scroll down */
+ *_scrollup, /* scroll up */
+ *_termcap_init, /* string to start termcap */
+ *_termcap_end, /* string to end termcap */
+ *_op, *_oc, *_setaf, *_setab, *_setf, *_setb, *_scp;
+int _colors, _pairs, _bce;
+char term_name[40];
+
+TERM term = {
+ NROW-1,
+ NCOL,
+ MARGIN,
+ MROW,
+ tcapopen,
+ tcapterminalinfo,
+ tcapclose,
+ ttgetc,
+ ttputc,
+ ttflush,
+ tcapmove,
+ tcapeeol,
+ tcapeeop,
+ tcapbeep,
+ tcaprev
+};
+
+
+/*
+ * Add default keypad sequences to the trie.
+ */
+static void
+setup_dflt_esc_seq(void)
+{
+ /*
+ * this is sort of a hack, but it allows us to use
+ * the function keys on pc's running telnet
+ */
+
+ /*
+ * UW-NDC/UCS vt10[02] application mode.
+ */
+ kpinsert("\033OP", F1, 1);
+ kpinsert("\033OQ", F2, 1);
+ kpinsert("\033OR", F3, 1);
+ kpinsert("\033OS", F4, 1);
+ kpinsert("\033Op", F5, 1);
+ kpinsert("\033Oq", F6, 1);
+ kpinsert("\033Or", F7, 1);
+ kpinsert("\033Os", F8, 1);
+ kpinsert("\033Ot", F9, 1);
+ kpinsert("\033Ou", F10, 1);
+ kpinsert("\033Ov", F11, 1);
+ kpinsert("\033Ow", F12, 1);
+
+ /*
+ * DEC vt100, ANSI and cursor key mode.
+ */
+ kpinsert("\033OA", KEY_UP, 1);
+ kpinsert("\033OB", KEY_DOWN, 1);
+ kpinsert("\033OC", KEY_RIGHT, 1);
+ kpinsert("\033OD", KEY_LEFT, 1);
+
+ /*
+ * special keypad functions
+ */
+ kpinsert("\033[4J", KEY_PGUP, 1);
+ kpinsert("\033[3J", KEY_PGDN, 1);
+ kpinsert("\033[2J", KEY_HOME, 1);
+ kpinsert("\033[N", KEY_END, 1);
+
+ /*
+ * vt220?
+ */
+ kpinsert("\033[5~", KEY_PGUP, 1);
+ kpinsert("\033[6~", KEY_PGDN, 1);
+ kpinsert("\033[1~", KEY_HOME, 1);
+ kpinsert("\033[4~", KEY_END, 1);
+
+ /*
+ * konsole, XTerm (XFree 4.x.x) keyboard setting
+ */
+ kpinsert("\033[H", KEY_HOME, 1);
+ kpinsert("\033[F", KEY_END, 1);
+
+ /*
+ * gnome-terminal 2.6.0, don't know why it
+ * changed from 2.2.1
+ */
+ kpinsert("\033OH", KEY_HOME, 1);
+ kpinsert("\033OF", KEY_END, 1);
+
+ /*
+ * "\033[2~" was common for KEY_HOME in a quick survey
+ * of terminals (though typically the Insert key).
+ * Teraterm 2.33 sends the following escape sequences,
+ * which is quite incompatible with everything
+ * else:
+ * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
+ * PgDn: "\033[6~"
+ * The best thing to do would be to fix TeraTerm
+ * keymappings or to tweak terminfo.
+ */
+
+ /*
+ * ANSI mode.
+ */
+ kpinsert("\033[=a", F1, 1);
+ kpinsert("\033[=b", F2, 1);
+ kpinsert("\033[=c", F3, 1);
+ kpinsert("\033[=d", F4, 1);
+ kpinsert("\033[=e", F5, 1);
+ kpinsert("\033[=f", F6, 1);
+ kpinsert("\033[=g", F7, 1);
+ kpinsert("\033[=h", F8, 1);
+ kpinsert("\033[=i", F9, 1);
+ kpinsert("\033[=j", F10, 1);
+ kpinsert("\033[=k", F11, 1);
+ kpinsert("\033[=l", F12, 1);
+
+ /*
+ * DEC vt100, ANSI and cursor key mode reset.
+ */
+ kpinsert("\033[A", KEY_UP, 1);
+ kpinsert("\033[B", KEY_DOWN, 1);
+ kpinsert("\033[C", KEY_RIGHT, 1);
+ kpinsert("\033[D", KEY_LEFT, 1);
+
+ /*
+ * DEC vt52 mode.
+ */
+ kpinsert("\033A", KEY_UP, 1);
+ kpinsert("\033B", KEY_DOWN, 1);
+ kpinsert("\033C", KEY_RIGHT, 1);
+ kpinsert("\033D", KEY_LEFT, 1);
+
+ /*
+ * DEC vt52 application keys, and some Zenith 19.
+ */
+ kpinsert("\033?r", KEY_DOWN, 1);
+ kpinsert("\033?t", KEY_LEFT, 1);
+ kpinsert("\033?v", KEY_RIGHT, 1);
+ kpinsert("\033?x", KEY_UP, 1);
+
+ /*
+ * Some Ctrl-Arrow keys
+ */
+ kpinsert("\033[5A", CTRL_KEY_UP, 1);
+ kpinsert("\033[5B", CTRL_KEY_DOWN, 1);
+ kpinsert("\033[5C", CTRL_KEY_RIGHT, 1);
+ kpinsert("\033[5D", CTRL_KEY_LEFT, 1);
+
+ kpinsert("\033[1;5A", CTRL_KEY_UP, 1);
+ kpinsert("\033[1;5B", CTRL_KEY_DOWN, 1);
+ kpinsert("\033[1;5C", CTRL_KEY_RIGHT, 1);
+ kpinsert("\033[1;5D", CTRL_KEY_LEFT, 1);
+
+ /*
+ * Map some shift+up/down/left/right to their shiftless counterparts
+ */
+ kpinsert("\033[1;2A", KEY_UP, 1);
+ kpinsert("\033[1;2B", KEY_DOWN, 1);
+ kpinsert("\033[1;2C", KEY_RIGHT, 1);
+ kpinsert("\033[1;2D", KEY_LEFT, 1);
+ kpinsert("\033[a", KEY_UP, 1);
+ kpinsert("\033[b", KEY_DOWN, 1);
+ kpinsert("\033[c", KEY_RIGHT, 1);
+ kpinsert("\033[d", KEY_LEFT, 1);
+
+ /*
+ * Sun Console sequences.
+ */
+ kpinsert("\033[1", KEY_SWALLOW_Z, 1);
+ kpinsert("\033[215", KEY_SWAL_UP, 1);
+ kpinsert("\033[217", KEY_SWAL_LEFT, 1);
+ kpinsert("\033[219", KEY_SWAL_RIGHT, 1);
+ kpinsert("\033[221", KEY_SWAL_DOWN, 1);
+
+ /*
+ * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
+ */
+ kpinsert("\033_", KEY_KERMIT, 1);
+
+ /*
+ * Fake a control character.
+ */
+ kpinsert("\033\033", KEY_DOUBLE_ESC, 1);
+}
+
+
+/*
+ * Read termcap and set some global variables. Initialize input trie to
+ * decode escape sequences.
+ */
+static int
+tcapterminalinfo(int termcap_wins)
+{
+ char *p, *tgetstr();
+ char tcbuf[2*1024];
+ char *tv_stype;
+ char err_str[72];
+ int err;
+ char *_ku, *_kd, *_kl, *_kr,
+ *_kppu, *_kppd, *_kphome, *_kpend, *_kpdel,
+ *_kf1, *_kf2, *_kf3, *_kf4, *_kf5, *_kf6,
+ *_kf7, *_kf8, *_kf9, *_kf10, *_kf11, *_kf12;
+
+ if (!(tv_stype = getenv("TERM")) || !strncpy(term_name, tv_stype, sizeof(term_name))){
+ if(Pmaster){
+ return(-1);
+ }
+ else{
+ puts("Environment variable TERM not defined!");
+ exit(1);
+ }
+ }
+
+ term_name[sizeof(term_name)-1] = '\0';
+
+ if((err = tgetent(tcbuf, tv_stype)) != 1){
+ if(Pmaster){
+ return(err - 2);
+ }
+ else{
+ snprintf(err_str, sizeof(err_str), "Unknown terminal type %s!", tv_stype);
+ puts(err_str);
+ exit(1);
+ }
+ }
+
+ p = tcapbuf;
+
+ _clearscreen = tgetstr("cl", &p);
+ _moveto = tgetstr("cm", &p);
+ _up = tgetstr("up", &p);
+ _down = tgetstr("do", &p);
+ _right = tgetstr("nd", &p);
+ _left = tgetstr("bs", &p);
+ _setinverse = tgetstr("so", &p);
+ _clearinverse = tgetstr("se", &p);
+ _setunderline = tgetstr("us", &p);
+ _clearunderline = tgetstr("ue", &p);
+ _setbold = tgetstr("md", &p);
+ _clearallattr = tgetstr("me", &p);
+ _cleartoeoln = tgetstr("ce", &p);
+ _cleartoeos = tgetstr("cd", &p);
+ _deletechar = tgetstr("dc", &p);
+ _insertchar = tgetstr("ic", &p);
+ _startinsert = tgetstr("im", &p);
+ _endinsert = tgetstr("ei", &p);
+ _deleteline = tgetstr("dl", &p);
+ _insertline = tgetstr("al", &p);
+ _scrollregion = tgetstr("cs", &p);
+ _scrolldown = tgetstr("sf", &p);
+ _scrollup = tgetstr("sr", &p);
+ _termcap_init = tgetstr("ti", &p);
+ _termcap_end = tgetstr("te", &p);
+ _startdelete = tgetstr("dm", &p);
+ _enddelete = tgetstr("ed", &p);
+ _ku = tgetstr("ku", &p);
+ _kd = tgetstr("kd", &p);
+ _kl = tgetstr("kl", &p);
+ _kr = tgetstr("kr", &p);
+ _kppu = tgetstr("kP", &p);
+ _kppd = tgetstr("kN", &p);
+ _kphome = tgetstr("kh", &p);
+ _kpend = tgetstr("kH", &p);
+ _kpdel = tgetstr("kD", &p);
+ _kf1 = tgetstr("k1", &p);
+ _kf2 = tgetstr("k2", &p);
+ _kf3 = tgetstr("k3", &p);
+ _kf4 = tgetstr("k4", &p);
+ _kf5 = tgetstr("k5", &p);
+ _kf6 = tgetstr("k6", &p);
+ _kf7 = tgetstr("k7", &p);
+ _kf8 = tgetstr("k8", &p);
+ _kf9 = tgetstr("k9", &p);
+ if((_kf10 = tgetstr("k;", &p)) == NULL)
+ _kf10 = tgetstr("k0", &p);
+ _kf11 = tgetstr("F1", &p);
+ _kf12 = tgetstr("F2", &p);
+
+ _colors = tgetnum("Co");
+ _pairs = tgetnum("pa");
+ _setaf = tgetstr("AF", &p);
+ _setab = tgetstr("AB", &p);
+ _setf = tgetstr("Sf", &p);
+ _setb = tgetstr("Sb", &p);
+ _scp = tgetstr("sp", &p);
+ _op = tgetstr("op", &p);
+ _oc = tgetstr("oc", &p);
+ _bce = tgetflag("ut");
+
+ if (p >= &tcapbuf[TCAPSLEN]){
+ puts("Terminal description too big!\n");
+ if(Pmaster)
+ return(-3);
+ else
+ exit(1);
+ }
+
+ _tlines = tgetnum("li");
+ if(_tlines == -1){
+ char *er;
+ int rr;
+
+ /* tgetnum failed, try $LINES */
+ er = getenv("LINES");
+ if(er && (rr = atoi(er)) > 0)
+ _tlines = rr;
+ }
+
+ _tcolumns = tgetnum("co");
+ if(_tcolumns == -1){
+ char *ec;
+ int cc;
+
+ /* tgetnum failed, try $COLUMNS */
+ ec = getenv("COLUMNS");
+ if(ec && (cc = atoi(ec)) > 0)
+ _tcolumns = cc;
+ }
+
+ /*
+ * Add default keypad sequences to the trie.
+ * Since these come first, they will override any conflicting termcap
+ * or terminfo escape sequences defined below. An escape sequence is
+ * considered conflicting if one is a prefix of the other.
+ * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
+ * escape sequences that don't work, because they conflict with default
+ * sequences defined here.
+ */
+ if(!termcap_wins)
+ setup_dflt_esc_seq();
+
+ /*
+ * add termcap/info escape sequences to the trie...
+ */
+
+ if(_ku != NULL && _kd != NULL && _kl != NULL && _kr != NULL){
+ kpinsert(_ku, KEY_UP, termcap_wins);
+ kpinsert(_kd, KEY_DOWN, termcap_wins);
+ kpinsert(_kl, KEY_LEFT, termcap_wins);
+ kpinsert(_kr, KEY_RIGHT, termcap_wins);
+ }
+
+ if(_kppu != NULL && _kppd != NULL){
+ kpinsert(_kppu, KEY_PGUP, termcap_wins);
+ kpinsert(_kppd, KEY_PGDN, termcap_wins);
+ }
+
+ kpinsert(_kphome, KEY_HOME, termcap_wins);
+ kpinsert(_kpend, KEY_END, termcap_wins);
+ kpinsert(_kpdel, KEY_DEL, termcap_wins);
+
+ kpinsert(_kf1, F1, termcap_wins);
+ kpinsert(_kf2, F2, termcap_wins);
+ kpinsert(_kf3, F3, termcap_wins);
+ kpinsert(_kf4, F4, termcap_wins);
+ kpinsert(_kf5, F5, termcap_wins);
+ kpinsert(_kf6, F6, termcap_wins);
+ kpinsert(_kf7, F7, termcap_wins);
+ kpinsert(_kf8, F8, termcap_wins);
+ kpinsert(_kf9, F9, termcap_wins);
+ kpinsert(_kf10, F10, termcap_wins);
+ kpinsert(_kf11, F11, termcap_wins);
+ kpinsert(_kf12, F12, termcap_wins);
+
+ /*
+ * Add default keypad sequences to the trie.
+ * Since these come after the termcap/terminfo escape sequences above,
+ * the termcap/info sequences will override any conflicting default
+ * escape sequences defined here.
+ * So, with TERMCAP_WINS, some of the default sequences will be missing.
+ * This means that you'd better get all of your termcap/terminfo entries
+ * correct if you define TERMCAP_WINS.
+ */
+ if(termcap_wins)
+ setup_dflt_esc_seq();
+
+ if(Pmaster)
+ return(0);
+ else
+ return(TRUE);
+}
+
+static int
+tcapopen(void)
+{
+ int row, col;
+
+ /*
+ * determine the terminal's communication speed and decide
+ * if we need to do optimization ...
+ */
+ if(ttisslow())
+ term_capabilities |= TT_OPTIMIZE;
+
+ col = _tcolumns;
+ row = _tlines;
+ if(row >= 0)
+ row--;
+
+ ttgetwinsz(&row, &col);
+ term.t_nrow = (short) row;
+ term.t_ncol = (short) col;
+
+ if(_cleartoeoln != NULL) /* able to use clear to EOL? */
+ term_capabilities |= TT_EOLEXIST;
+ else
+ term_capabilities &= ~TT_EOLEXIST;
+
+ if(_setinverse != NULL)
+ term_capabilities |= TT_REVEXIST;
+ else
+ term_capabilities &= ~TT_REVEXIST;
+
+ if(_deletechar == NULL && (_startdelete == NULL || _enddelete == NULL))
+ term_capabilities &= ~TT_DELCHAR;
+
+ if(_insertchar == NULL && (_startinsert == NULL || _endinsert == NULL))
+ term_capabilities &= ~TT_INSCHAR;
+
+ if((_scrollregion == NULL || _scrolldown == NULL || _scrollup == NULL)
+ && (_deleteline == NULL || _insertline == NULL))
+ term_capabilities &= ~TT_SCROLLEXIST;
+
+ if(_clearscreen == NULL || _moveto == NULL || _up == NULL){
+ if(Pmaster == NULL){
+ puts("Incomplete termcap entry\n");
+ exit(1);
+ }
+ }
+
+ ttopen();
+
+ if(_termcap_init && !Pmaster) {
+ putpad(_termcap_init); /* any init termcap requires */
+ if (_scrollregion)
+ putpad(tgoto(_scrollregion, term.t_nrow, 0)) ;
+ }
+
+ /*
+ * Initialize UW-modified NCSA telnet to use it's functionkeys
+ */
+ if(gmode&MDFKEY && Pmaster == NULL)
+ puts("\033[99h");
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tcapclose(void)
+{
+ if(!Pmaster){
+ if(gmode&MDFKEY)
+ puts("\033[99l"); /* reset UW-NCSA telnet keys */
+
+ if(_termcap_end) /* any cleanup termcap requires */
+ putpad(_termcap_end);
+ }
+
+ ttclose();
+
+ /* return ignored */
+ return(0);
+}
+
+
+
+/*
+ * tcapinsert - insert a character at the current character position.
+ * _insertchar takes precedence.
+ */
+static void
+tcapinsert(UCS ch)
+{
+ if(_insertchar != NULL){
+ putpad(_insertchar);
+ ttputc(ch);
+ }
+ else{
+ putpad(_startinsert);
+ ttputc(ch);
+ putpad(_endinsert);
+ }
+}
+
+
+/*
+ * tcapdelete - delete a character at the current character position.
+ */
+static void
+tcapdelete(void)
+{
+ if(_startdelete == NULL && _enddelete == NULL)
+ putpad(_deletechar);
+ else{
+ putpad(_startdelete);
+ putpad(_deletechar);
+ putpad(_enddelete);
+ }
+}
+
+
+/*
+ * o_scrolldown - open a line at the given row position.
+ * use either region scrolling or deleteline/insertline
+ * to open a new line.
+ */
+int
+o_scrolldown(int row, int n)
+{
+ register int i;
+
+ if(_scrollregion != NULL){
+ putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
+ tcapmove(row, 0);
+ for(i = 0; i < n; i++)
+ putpad( (_scrollup != NULL && *_scrollup != '\0')
+ ? _scrollup : "\n" );
+ putpad(tgoto(_scrollregion, term.t_nrow, 0));
+ tcapmove(row, 0);
+ }
+ else{
+ /*
+ * this code causes a jiggly motion of the keymenu when scrolling
+ */
+ for(i = 0; i < n; i++){
+ tcapmove(term.t_nrow - (term.t_mrow+1), 0);
+ putpad(_deleteline);
+ tcapmove(row, 0);
+ putpad(_insertline);
+ }
+#ifdef NOWIGGLYLINES
+ /*
+ * this code causes a sweeping motion up and down the display
+ */
+ tcapmove(term.t_nrow - term.t_mrow - n, 0);
+ for(i = 0; i < n; i++)
+ putpad(_deleteline);
+ tcapmove(row, 0);
+ for(i = 0; i < n; i++)
+ putpad(_insertline);
+#endif
+ }
+
+ /* return ignored */
+ return(0);
+}
+
+
+/*
+ * o_scrollup - open a line at the given row position.
+ * use either region scrolling or deleteline/insertline
+ * to open a new line.
+ */
+int
+o_scrollup(int row, int n)
+{
+ register int i;
+
+ if(_scrollregion != NULL){
+ putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
+ /* setting scrolling region moves cursor to home */
+ tcapmove(term.t_nrow-(term.t_mrow+1), 0);
+ for(i = 0;i < n; i++)
+ putpad((_scrolldown == NULL || _scrolldown[0] == '\0')
+ ? "\n" : _scrolldown);
+ putpad(tgoto(_scrollregion, term.t_nrow, 0));
+ tcapmove(2, 0);
+ }
+ else{
+ for(i = 0; i < n; i++){
+ tcapmove(row, 0);
+ putpad(_deleteline);
+ tcapmove(term.t_nrow - (term.t_mrow+1), 0);
+ putpad(_insertline);
+ }
+#ifdef NOWIGGLYLINES
+ /* see note above */
+ tcapmove(row, 0);
+ for(i = 0; i < n; i++)
+ putpad(_deleteline);
+ tcapmove(term.t_nrow - term.t_mrow - n, 0);
+ for(i = 0;i < n; i++)
+ putpad(_insertline);
+#endif
+ }
+
+ /* return ignored */
+ return(0);
+}
+
+
+/*
+ * o_insert - use termcap info to optimized character insert
+ * returns: true if it optimized output, false otherwise
+ */
+int
+o_insert(UCS c)
+{
+ if(term_capabilities & TT_INSCHAR){
+ tcapinsert(c);
+ return(1); /* no problems! */
+ }
+
+ return(0); /* can't do it. */
+}
+
+
+/*
+ * o_delete - use termcap info to optimized character insert
+ * returns true if it optimized output, false otherwise
+ */
+int
+o_delete(void)
+{
+ if(term_capabilities & TT_DELCHAR){
+ tcapdelete();
+ return(1); /* deleted, no problem! */
+ }
+
+ return(0); /* no dice. */
+}
+
+
+static int
+tcapmove(int row, int col)
+{
+ putpad(tgoto(_moveto, col, row));
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tcapeeol(void)
+{
+ int c, starting_col, starting_line;
+ char *last_bg_color;
+
+ /*
+ * If the terminal doesn't have back color erase, then we have to
+ * erase manually to preserve the background color.
+ */
+ if(pico_usingcolor() && (!_bce || !_cleartoeoln)){
+ extern int ttcol, ttrow;
+
+ starting_col = ttcol;
+ starting_line = ttrow;
+ last_bg_color = pico_get_last_bg_color();
+ pico_set_nbg_color();
+ for(c = ttcol; c < term.t_ncol; c++)
+ ttputc(' ');
+
+ tcapmove(starting_line, starting_col);
+ if(last_bg_color){
+ pico_set_bg_color(last_bg_color);
+ free(last_bg_color);
+ }
+ }
+ else if(_cleartoeoln)
+ putpad(_cleartoeoln);
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tcapeeop(void)
+{
+ int i, starting_col, starting_row;
+
+ /*
+ * If the terminal doesn't have back color erase, then we have to
+ * erase manually to preserve the background color.
+ */
+ if(pico_usingcolor() && (!_bce || !_cleartoeos)){
+ extern int ttcol, ttrow;
+
+ starting_col = ttcol;
+ starting_row = ttrow;
+ tcapeeol(); /* rest of this line */
+ for(i = ttrow+1; i <= term.t_nrow; i++){ /* the remaining lines */
+ tcapmove(i, 0);
+ tcapeeol();
+ }
+
+ tcapmove(starting_row, starting_col);
+ }
+ else if(_cleartoeos)
+ putpad(_cleartoeos);
+
+ /* return ignored */
+ return(0);
+}
+
+
+static int
+tcaprev(int state) /* change reverse video status */
+{ /* FALSE = normal video, TRUE = reverse video */
+ if(state)
+ StartInverse();
+ else
+ EndInverse();
+
+ return(1);
+}
+
+
+static int
+tcapbeep(void)
+{
+ ttputc(BELL);
+
+ /* return ignored */
+ return(0);
+}
+
+
+void
+putpad(char *str)
+{
+ tputs(str, 1, putchar);
+}
+
+#else /* HARD_CODED_ANSI_TERMINAL */
+
+/*
+ * ANSI-specific terminal i/o and control routines
+ */
+
+
+#define BEL 0x07 /* BEL character. */
+#define ESC 0x1B /* ESC character. */
+
+
+extern int ttflush();
+
+extern int ansimove(int, int);
+extern int ansieeol(void);
+extern int ansieeop(void);
+extern int ansibeep(void);
+extern int ansiparm(int);
+extern int ansiopen(void);
+extern int ansiterminalinfo(int);
+extern int ansirev(int);
+
+/*
+ * Standard terminal interface dispatch table. Most of the fields point into
+ * "termio" code.
+ */
+#if defined(VAX) && !defined(__ALPHA)
+globaldef
+#endif
+
+TERM term = {
+ NROW-1,
+ NCOL,
+ MARGIN,
+ MROW,
+ ansiopen,
+ ansiterminalinfo,
+ ttclose,
+ ttgetc,
+ ttputc,
+ ttflush,
+ ansimove,
+ ansieeol,
+ ansieeop,
+ ansibeep,
+ ansirev
+};
+
+int
+ansimove(int row, int col)
+{
+ ttputc(ESC);
+ ttputc('[');
+ ansiparm(row+1);
+ ttputc(';');
+ ansiparm(col+1);
+ ttputc('H');
+}
+
+int
+ansieeol(void)
+{
+ ttputc(ESC);
+ ttputc('[');
+ ttputc('K');
+}
+
+int
+ansieeop(void)
+{
+ ttputc(ESC);
+ ttputc('[');
+ ttputc('J');
+}
+
+int
+ansirev(int state) /* change reverse video state */
+{ /* TRUE = reverse, FALSE = normal */
+ static int PrevState = 0;
+
+ if(state != PrevState) {
+ PrevState = state ;
+ ttputc(ESC);
+ ttputc('[');
+ ttputc(state ? '7': '0');
+ ttputc('m');
+ }
+}
+
+int
+ansibeep(void)
+{
+ ttputc(BEL);
+ ttflush();
+}
+
+int
+ansiparm(int n)
+{
+ register int q;
+
+ q = n/10;
+ if (q != 0)
+ ansiparm(q);
+ ttputc((n%10) + '0');
+}
+
+
+int
+ansiterminalinfo(int termcap_wins)
+{
+#if V7
+ register char *cp;
+ char *getenv();
+
+ if ((cp = getenv("TERM")) == NULL) {
+ puts("Shell variable TERM not defined!");
+ exit(1);
+ }
+ if (strcmp(cp, "vt100") != 0) {
+ puts("Terminal type not 'vt100'!");
+ exit(1);
+ }
+#endif
+ /* revexist = TRUE; dead code? */
+}
+
+int
+ansiopen(void)
+{
+ ttopen();
+}
+
+
+#endif /* HARD_CODED_ANSI_TERMINAL */
+#else /* _WINDOWS */
+
+/* These are all just noops in Windows */
+
+unsigned
+tthascap(void)
+{
+ return(0);
+}
+
+/*
+ * o_insert - optimize screen insert of char c
+ */
+int
+o_insert(UCS c)
+{
+ return(0);
+}
+
+
+/*
+ * o_delete - optimized character deletion
+ */
+int
+o_delete(void)
+{
+ return(0);
+}
+
+
+
+#endif /* _WINDOWS */