/* C K O C O 3 . C */

/*
  Authors: Frank da Cruz (fdc@columbia.edu),
             Columbia University Academic Information Systems, New York City.
           Jeffrey E Altman (jaltman@secure-endpoints.com)
             Secure Endpoints Inc., New York City
           David Goodwin (david@zx.net.nz)

  Copyright (C) 1985, 2004, Trustees of Columbia University in the City of
  New York.  All rights reserved.  This copyright notice must not be removed,
  altered, or obscured.
*/

#include "ckcdeb.h"             /* Typedefs, debug formats, etc */
#include "ckcker.h"             /* Kermit definitions */
#include "ckcasc.h"             /* ASCII character symbols */
#include "ckcnet.h"             /* Network support */
#include "ckuusr.h"             /* For terminal type definitions, etc. */
#include "ckcxla.h"             /* Character set translation */
#include "ckcuni.h"             /* Unicode Character Set Translations */
#ifndef NOLOCAL
#include "ckowys.h"
#include "ckodg.h"
#include "ckoava.h"
#include "ckotvi.h"
#include "ckohzl.h"
#include "ckohp.h"
#include "ckovc.h"
#include "ckoi31.h"
#include "ckoqnx.h"
#include "ckoadm.h"
#include "ckoads.h"
#include "ckosnd.h"
#endif /* NOLOCAL */

#include <ctype.h>              /* Character types */
#include <io.h>                 /* File io function declarations */
#include <process.h>            /* Process-control function declarations */
#include <stdlib.h>             /* Standard library declarations */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <math.h>

#define DECLED

#ifdef NT
#include <windows.h>
#else /* NT */

#ifdef OS2MOUSE
#define INCL_MOU
#endif /* OS2MOUSE */

#define INCL_NOPM
#define INCL_VIO
#define INCL_ERRORS
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSDEVIOCTL
#define INCL_WINCLIPBOARD
#include <os2.h>
#undef COMMENT                /* COMMENT is defined in os2.h */
#endif /* NT */
#include "ckocon.h"             /* definitions common to console routines */

#ifndef NOLOCAL
#include "ckokey.h"
#include "ckotek.h"
#include "ckowin.h"

#ifdef CK_NETBIOS
#include "ckonbi.h"
extern UCHAR NetBiosRemote[] ;
#endif /* CK_NETBIOS */

#ifdef KUI
#include "ikui.h"
#endif /* KUI */

#ifdef SSHBUILTIN
#include "ckossh.h"
#endif

#ifdef NETCONN
#ifdef TCPSOCKET
#ifdef CK_NAWS
_PROTOTYP( int tn_snaws, (void) );
#ifdef RLOGCODE
_PROTOTYP( int rlog_naws, (void) ) ;
#endif /* RLOGCODE */
#ifdef SSHBUILTIN
_PROTOTYP( int ssh_snaws, (void));
#endif /* SSHBUILTIN */
extern int me_naws;
#endif /* CK_NAWS */

extern int tn_rem_echo;
extern int tcp_incoming;
#endif /* TCPSOCKET */
#endif /* NETCONN */

_PROTOTYP(void vtescape, (void));
_PROTOTYP(void vt100, (unsigned short vtch));
char* csetchar(enum charsetsize size, int cset);
#endif /* NOLOCAL */

#ifdef KUI
int gui_resize_pixels(int, int);    /* cknwin.c */
int gui_position(int, int);         /* cknwin.c */
int gui_win_run_mode(int);          /* cknwin.c */
int gui_resize_mode(int);           /* cknwin.c */
#endif /* KUI */

_PROTOTYP( int os2getcp, (void) );  /* ckotio.c */
int os2settitle(char *, int);       /* ckotio.c */
VOID seturlhl(int);                 /* ckuus7.c */
void os2push();                     /* ckocon.c */
void setborder();                   /* ckocon.c */
int fc2tx(int fc);                  /* ckcuni.c */
USHORT tx_lucidasub(USHORT);    /* ckcuni.c */
USHORT tx_usub(USHORT);         /* ckcuni.c */
USHORT tx_hslsub(USHORT);       /* ckcuni.c */

#ifndef NOSPL
/* struct mtab [] exists only if NOSPL isn't defined */
int mlook( struct mtab [], char *, int );
int mxlook( struct mtab [], char *, int );
#endif /* NOSPL */

#ifdef OS2MOUSE
void mouseurl(int, USHORT, USHORT); /* ckomou.c */
#endif /* OS2MOUSE */

#ifdef PCTERM
VOID setpcterm(int);                /* ckokey.c */
#endif /* PCTERM */

#ifdef NT
int prtcfg(HANDLE);                 /* ckotio.c */
#endif /* NT */

int cursor_right_margin(int);
int cursor_left_margin(int);
bool cursor_in_margins(int);

/* These terminal types get DECLRMM */
#define IS_DECLRMM_AVAILABLE(x) (ISVT420((x)) || ISXTERM((x)) || ISK95((x)))

/*
 *
 * =============================externals=====================================
 */
extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR);  /* Character set xlate */
extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR);  /* functions. */
extern char     *printername;
extern int      printpipe;
#ifdef BPRINT
extern int  printbidi;                  /* SET BPRINTER (bidirectional) */
#endif /* BPRINT */
bool winprint = FALSE;
FILE *lst=NULL;                 /* List (print) device */
#ifdef NT
_PROTOTYP(int Win32PrtOpen, (char *));
_PROTOTYP(int Win32PrtWrite, (char *, int));
_PROTOTYP(int Win32PrtClose, (void));
#endif /* NT */
static time_t printerclose_t=0;
bool     printon        = FALSE; /* Printer is on */

#ifdef NT
_PROTOTYP( FILE * win95popen, (const char *cmd, const char *mode) );
_PROTOTYP( int win95pclose, (FILE *pipe) );
#define popen _popen
#define pclose _pclose
#else /* NT */
#ifdef __WATCOMC__
#define popen _popen
#define pclose _pclose
#endif
#endif /* NT */

#ifdef COMMENT
_PROTOTYP( FILE * popen, (const char *cmd, const char *mode));
_PROTOTYP( int pclose, (FILE *pipe));
#endif /* COMMENT */

#ifndef NOLOCAL
extern struct csinfo fcsinfo[]; /* File character set info */
extern int tcsr, tcsl;          /* Terminal character sets, remote & local. */
extern int prncs;               /* Printer Character Set */
extern int tcs_transp;

extern int ttmdm;
extern int tnlm, tn_nlm;        /* Terminal newline mode, ditto for TELNET */
extern int tn_b_nlm ;           /* TELNET BINARY newline mode */
extern int tt_crd;              /* Carriage-return display mode */
extern int tt_lfd;              /* Line-feed display mode */
extern int tt_bell;             /* How to handle incoming Ctrl-G characters */
extern int tt_bell_usr;
#ifdef KUI
extern int tt_bell_flash;
extern int user_bell_flash;
extern int tt_bell_raise;
#endif /* KUI */
extern int tt_type, tt_type_mode ;
extern int tt_status[VNUM];           /* Terminal status line displayed */
extern int tt_status_usr[VNUM];
extern int tt_modechg;          /* Terminal Video-Change (80 or 132 cols) */
extern int tt_senddata;         /* May data be sent to the host */
extern int tt_clipboard_read,
           tt_clipboard_write;  /* OSC-52 */
extern int tt_hidattr;          /* Attributes do not occupy a space */
#ifdef NT
extern int tt_autorepeat;       /* Keyboard autorepeat */
#endif /* NT */
#ifdef PCTERM
extern int tt_pcterm;
#endif /* PCTERM */
extern int ttyfd, Shutdown ;
#ifdef CK_TAPI
extern int tttapi;
#endif /* CK_TAPI */
#ifdef KUI
extern CKFLOAT  tt_linespacing[VNUM];
#endif /* KUI */
#ifdef OS2MOUSE
extern int      mouse_reporting_mode;
#endif /* OS2MOUSE */
extern long     speed, vernum;
extern int      local, escape, duplex, parity, flow, seslog, pmask,
                cmdmsk, cmask, sosi, xitsta, debses, mdmtyp, carrier, what;
extern int      cflg, cnflg, stayflg, tt_escape, tt_scroll, tt_term_scroll;
extern int      network, nettype, ttnproto, protocol, inautodl;
extern int cmdlvl,tlevel, ckxech;
extern int ttnum;                               /* from ckcnet.c */
extern int tt_async;
#ifndef NOXFER
extern int      autodl, adl_ask;
int adl_kc0 = TRUE,
    adl_zc0 = TRUE;     /* Process autodownload C0 chars by emulation */
extern int adl_err, xferstat;
extern CHAR stchr;
#endif /* NOXFER */
int duplex_sav = -1 ;

#ifndef NOSPL
extern struct mtab *mactab;             /* Main macro table */
extern int nmac;                        /* Number of macros */
#endif /* NOSPL */
#ifdef TNCODE
extern int tn_deb;
#endif /* TNCODE */

extern KEY      *keymap;
extern MACRO    *macrotab;
extern char     ttname[], sesfil[];
#ifndef NODIAL
extern char     * d_name;
#endif /* NODIAL */

extern int  scrninitialized[] ;
extern bool scrollflag[] ;
extern bool viewonly ;           /* View Only Terminal mode */
#ifdef KUI
extern int  scrollmode ;            /* Fast/Smooth scrolling */
extern bool in_smooth_scroll, in_bg_smooth_scroll ;
extern int smooth_speed;
extern int smooth_speed_pending;
extern int tt_smooth_speed;
extern DWORD bg_smooth_scroll_ends;
#else
extern int updmode;
extern int tt_updmode;
#endif /* KUI */
extern int priority ;
extern TID  tidRdComWrtScr ;

#ifdef CK_XYZ
extern int p_avail ;
#endif /* CK_XYZ */

extern int beepfreq, beeptime ;
extern int pwidth, pheight;
extern int win95lucida, win95hsl;

#ifdef KUI
int transmit_focus_change = FALSE;
#endif /* KUI */

/*
 * =============================variables==============================
 */

/*
  These are RGB bits for the fore- and background colors in the PC's video
  adapter, 3 bits for each color.  These default values can be changed by the
  SET TERMINAL COLOR command (in ckuus7.c) or by CSI3x;4xm escape sequences
  from the host.
*/
cell_video_attr_t     colornormal     = cell_video_attr_init_vio_attribute(0x17);
cell_video_attr_t     colorunderline  = cell_video_attr_init_vio_attribute(0x47);
cell_video_attr_t     colordebug      = cell_video_attr_init_vio_attribute(0x47);
cell_video_attr_t     colorreverse    = cell_video_attr_init_vio_attribute(0x71);
cell_video_attr_t     colorgraphic    = cell_video_attr_init_vio_attribute(0x17);
#ifdef COMMENT
cell_video_attr_t     colorstatus     = cell_video_attr_init_vio_attribute(0x37);
cell_video_attr_t     colorhelp       = cell_video_attr_init_vio_attribute(0x37);
#else /* COMMENT */
cell_video_attr_t     colorstatus     = cell_video_attr_init_vio_attribute(0x71);
cell_video_attr_t     colorhelp       = cell_video_attr_init_vio_attribute(0x71);
#endif /* COMMENT */
cell_video_attr_t     colorselect     = cell_video_attr_init_vio_attribute(0xe0);
cell_video_attr_t     savedcolorselect= cell_video_attr_init_vio_attribute(0xe0);
cell_video_attr_t     colorborder     = cell_video_attr_init_vio_attribute(0x01);
cell_video_attr_t     coloritalic     = cell_video_attr_init_vio_attribute(0x27);
cell_video_attr_t     colorblink      = cell_video_attr_init_vio_attribute(0x87);
cell_video_attr_t     colorbold       = cell_video_attr_init_vio_attribute(0x0F);
cell_video_attr_t     colorcrossedout = cell_video_attr_init_vio_attribute(0x10);
#ifdef CK_COLORS_24BIT
/* Entry 8 in the VT525 palette is black, so if we can default these to RGB */
cell_video_attr_t     colordim        = cell_video_attr_init_rgb_attribute(192, 192, 192, 0, 0, 0);
cell_video_attr_t     colorcursor     = cell_video_attr_init_rgb_attribute(0, 0, 0, 192, 192, 192);
cell_video_attr_t     savedcolorcursor= cell_video_attr_init_rgb_attribute(0, 0, 0, 192, 192, 192);
#else /* CK_COLORS_24BIT */
cell_video_attr_t     colordim        = cell_video_attr_init_vio_attribute(0x08);
cell_video_attr_t     colorcursor     = cell_video_attr_init_vio_attribute(0x80);
cell_video_attr_t     savedcolorcursor= cell_video_attr_init_vio_attribute(0x80);
#endif /* CK_COLORS_24BIT */

int bgi = FALSE, fgi = FALSE ;
cell_video_attr_t colorcmd        = cell_video_attr_init_vio_attribute(0x07);
int colorreset    = TRUE ;  /* reset on CSI 0 m - use normal colors */
int erasemode     = FALSE ; /* Use current colors when erasing characters */
int user_erasemode= FALSE ; /* Use current colors when erasing characters */
int trueblink     = TRUE ;
int blink_is_color = FALSE ;  /* Use a color rather than intensity for simulated blink */
int bold_is_color = FALSE ;   /* Use a color rather than intensity for bold */
int dim_is_color = FALSE ;    /* Use a color rather than intensity for dim */
int use_bold_attr = FALSE;
int use_blink_attr = FALSE;
int truereverse   = TRUE ;
int trueunderline = TRUE ;
int truedim       = TRUE ;
int truebold      = TRUE ;
int bold_font_only = FALSE;    /* Only do a bold font, not bold + bright? */
#ifdef KUI
int trueitalic    = TRUE ;
int truecrossedout = TRUE;
#else /* KUI */
int trueitalic    = FALSE ;
int truecrossedout = FALSE;
#endif /* KUI */
int colorAttPriority = TRUE ; /* Attribute colors take priority over SGR colors */
/* xterm defaults this to FALSE, while K95 defaults it to TRUE */

/* These are so that any changes to the true* attribute settings by OSC6/106
 * or similar can be reverted on terminal reset. */
int savedtrueblink     = TRUE;
int savedtruereverse   = TRUE;
int savedtrueunderline = TRUE;
int savedtruedim       = TRUE ;
int savedtruebold      = TRUE ;
#ifdef KUI
int savedtrueitalic    = TRUE ;
int savedtruecrossedout = TRUE;
#else /* KUI */
int savedtrueitalic    = FALSE ;
int savedtruecrossedout = FALSE ;
#endif /* KUI */

enum markmodes markmodeflag[VNUM] = {notmarking, notmarking,
                                                notmarking, notmarking} ;

extern int tn_bold;                     /* TELNET negotiation bold */
extern int esc_exit;                    /* Escape back = exit */
extern char * esc_msg;
extern int interm ;                     /* INPUT echo state */
extern BYTE vmode ;

long waittime;                  /* Timeout on CTS during CONNECT */
#define INTERVAL 100L

char termessage[MAXTERMCOL];

#ifdef CK_APC
extern int apcactive;                   /* Application Program Command (APC) */
extern int apccmd;						/* Remain on command screen after APC */
int apcrecv = 0;
int dcsrecv = 0;                        /* Device Control String (DCS) */
int oscrecv = 0;                        /* Operating System Command (OSC) */
int oscterm = 0;                        /* OSC string terminator */
int pmrecv  = 0;                        /* Private Message (PM) */
int pu1recv = 0;                        /* 97801-5xx Private Use One (PU1) */
int pu2recv = 0;                        /* 97801-5xx Private Use Two (PU2) */
int c1strrecv = 0;                      /* Other generic C1 strings */
extern int apcstatus;                   /* items ... */
#ifdef DCMDBUF
extern char *apcbuf;
#else
extern char apcbuf[];
#endif /* DCMDBUF */
int apclength = 0;
int apcbuflen = APCBUFLEN - 2;
#endif /* CK_APC */

extern char * keydefptr;
extern int keymac;
extern int keymacx ;

bool scrollstatus[VNUM] = {FALSE,FALSE,FALSE,FALSE} ;
bool escapestatus[VNUM] = {FALSE,FALSE,FALSE,FALSE} ;
extern int tt_idlelimit;                /* Auto-exit Connect when idle */
extern int tt_timelimit;                /* Auto-exit Connect after time */
extern bool flipscrnflag[] ;


extern vscrn_t vscrn[];

extern ascreen                          /* For saving screens: */
  vt100screen,                          /* terminal screen */
  commandscreen ;                       /* OS/2 screen */

extern ascreen mousescreen; /* Screen during mouse actions */

/* How many saved cursor slots - one for each vscrn, plus one for the xterm
 * alternate screen. */
#define SAVED_CURSORS VNUM+1
#define XT_ALTBUF_CURSOR_SLOT VNUM

cell_video_attr_t                       /* Video attribute bytes */
    attribute=cell_video_attr_init_vio_attribute(0), /* Current video attribute byte */
    underlineattribute=cell_video_attr_init_vio_attribute(0),
    savedattribute[SAVED_CURSORS]={0,0,0,0,0},       /* Saved video attribute byte */
    saveddefaultattribute[SAVED_CURSORS]={0,0,0,0,0},/* Saved video attribute byte */
    savedunderlineattribute[SAVED_CURSORS]={0,0,0,0,0},/* Saved video attribute byte */
    defaultattribute=cell_video_attr_init_vio_attribute(0),  /* Default video attribute byte */
    italicattribute=cell_video_attr_init_vio_attribute(0),   /* Default video attribute byte */
    saveditalicattribute[SAVED_CURSORS]={0,0,0,0,0},
    reverseattribute=cell_video_attr_init_vio_attribute(0),
    savedreverseattribute[SAVED_CURSORS]={0,0,0,0,0},
    graphicattribute=cell_video_attr_init_vio_attribute(0),
    savedgraphicattribute[SAVED_CURSORS]={0,0,0,0,0},
    borderattribute=cell_video_attr_init_vio_attribute(0),
    savedborderattribute[SAVED_CURSORS]={0,0,0,0,0},
    blinkattribute=cell_video_attr_init_vio_attribute(0),
    savedblinkattribute[SAVED_CURSORS]={0,0,0,0,0},
    boldattribute=cell_video_attr_init_vio_attribute(0),
    savedboldattribute[SAVED_CURSORS]={0,0,0,0,0},
	dimattribute=cell_video_attr_init_vio_attribute(0),
    saveddimattribute[SAVED_CURSORS]={0,0,0,0,0},
    crossedoutattribute=cell_video_attr_init_vio_attribute(0),
    savedcrossedoutattribute[SAVED_CURSORS]={0,0,0,0,0}
    ;

cell_video_attr_t decatc_colors[16];

vtattrib attrib={0,0,0,0,0,0,0,0,0,0,0,0,0,0},
         savedattrib[SAVED_CURSORS]={
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
         cmdattrib={0,0,0,0,0,0,0,0,0,0,0,0,0,0};

extern int wherex[];                    /* Screen column, 1-based */
extern int wherey[];                    /* Screen row, 1-based */

extern int quitnow, hangnow, outshift, tcs, langsv;

int term_io = TRUE;                     /* Terminal emulator performs I/O */

int prevchar = 0;                       /* Last char written to terminal screen */

extern char answerback[81];             /* answerback */
extern char usertext[(MAXTERMCOL) + 1];        /* Status line and its parts */
extern char statusline[MAXTERMCOL + 1];
char hoststatusline[MAXTERMCOL + 1];
extern char exittext[(30) + 1];     /* Used to be (20)+1, bumped to fit some longer key names */
#define HLPTXTLEN 41
extern char helptext[HLPTXTLEN];
extern char filetext[(20) + 1];
char savefiletext[(20) + 1] = { NUL };
#define HSTNAMLEN 41
extern char hostname[HSTNAMLEN];

#define DEFTABS \
"0\
T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000\
T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000\
T00000";

char htab[MAXTERMCOL+2] = DEFTABS       /* Default tab settings */

static int achar;                       /* Global - current character */
int tt_utf8 = 0;                        /* Is UTF8 mode active ? */

struct _vtG G[4] = {
    TX_ASCII,   TX_ASCII,  cs94, cs94, TRUE,  TRUE, TRUE, NULL, NULL, NULL, NULL, TRUE,
    TX_8859_1,  TX_8859_1, cs96, cs96, FALSE, TRUE, TRUE, NULL, NULL, NULL, NULL, TRUE,
    TX_8859_1,  TX_8859_1, cs96, cs96, FALSE, TRUE, TRUE, NULL, NULL, NULL, NULL, TRUE,
    TX_8859_1,  TX_8859_1, cs96, cs96, FALSE, TRUE, TRUE, NULL, NULL, NULL, NULL, TRUE
    };
struct _vtG *GL = &G[0], *SSGL = NULL;   /* GL and single shift GL */
struct _vtG *GR = &G[2];                 /* GR */
struct _vtG *GNOW = &G[0];
struct _vtG savedG[SAVED_CURSORS][4];
struct _vtG *savedGL[SAVED_CURSORS] = {NULL,NULL,NULL,NULL,NULL},
            *savedGR[SAVED_CURSORS] = {NULL,NULL,NULL,NULL,NULL},
            *savedSSGL[SAVED_CURSORS] = {NULL,NULL,NULL,NULL,NULL} ;
static int  Qsaved = FALSE;              /* QANSI charset shifts */
struct _vtG QsavedG[4],
            *QsavedGL = NULL,
            *QsavedGR = NULL,
            *QsavedSSGL = NULL;

bool     printregion    = FALSE; /* Print extent = full screen */
bool     xprintff       = FALSE; /* Print formfeed */
bool     turnonprinter  = FALSE; /* Time to turn on printer */
bool     xprint         = FALSE; /* Controller print in progress */
bool     aprint         = FALSE; /* Auto-print in progress */
bool     cprint         = FALSE; /* Copy-print in progress (for debug) */
bool     uprint         = FALSE; /* Transparent print */
bool     turnoffprinter = FALSE; /* Time to turn it off */

bool     wrapit    = FALSE;        /* Last column flag */
bool     literal_ch= FALSE;
bool     screenon  = TRUE;
extern bool     cursorena[];       /* Cursor enabled / disabled */
extern bool     cursoron[] ;       /* Cursor state on/off       */
extern bool     bracketed_paste[]; /* Bracketed paste on/off    */
bool     relcursor = FALSE;
bool     declrmm   = FALSE;			/* VT420 Left/Right Margin Mode */
bool     keylock   = FALSE;
bool     vt52graphics = FALSE;

bool     saverelcursor[SAVED_CURSORS]={FALSE,FALSE,FALSE,FALSE,FALSE},
         saved[SAVED_CURSORS]={FALSE,FALSE,FALSE,FALSE,FALSE};
int      savedwrap[SAVED_CURSORS]={FALSE,FALSE,FALSE,FALSE,FALSE} ;
int      savedrow[SAVED_CURSORS] = {0,0,0,0,0};
int      savedcol[SAVED_CURSORS] = {0,0,0,0,0};
int      savedpage[SAVED_CURSORS] = {0,0,0,0,0};
bool     savedlcf[SAVED_CURSORS] = {FALSE,FALSE,FALSE,FALSE,FALSE};
extern int      tt_rkeys_saved[], tt_rkeys[];

bool     deccolm = FALSE;               /* 80/132-column mode */
bool     decscnm = FALSE;               /* Normal/reverse screen mode */
int      decscnm_usr = FALSE;           /* User default for decscnm */
bool     decnrcm = FALSE ;              /* National Replacement Charset mode */
int      decnrcm_usr = FALSE;           /* NRC mode - user default */
bool     decsasd = SASD_TERMINAL ;      /* Active Status Display */
int      decssdt = SSDT_INDICATOR ;     /* Status Display Type */
bool     decssdt_override = FALSE;      /* Render SSDT_INDICATOR regardless of decssdt */
bool     deckbum = FALSE ;              /* Keyboard (Typewriter/DP) */
bool     decsace = FALSE;               /* DECSACE */
bool     decncsm = FALSE;               /* No clearing screen on column change */
bool     decncsm_usr = FALSE;           /* User setting for DECNCSM */
bool     decscpp_resize = FALSE;        /* Resize initiated by DECSCPP */
int      savdecbkm = 0 ;                /* User default Backspace Mode */
bool     erm = FALSE ;                  /* Erasure Mode  VT300 */
bool     crm = FALSE ;                  /* Control Mode  VT300 */
bool     decled[4] = {FALSE,FALSE,FALSE,FALSE} ; /* DEC LEDs */
bool     insertmode = FALSE;            /* Insert/replace mode */
bool     sco8bit = FALSE;               /* SCO ANSI 8th bit quoting */
bool     scoBCS2 = FALSE;               /* SCO ANSI BCS2 */
bool     scocompat = FALSE;             /* SCO ANSI Backward Compatibility Mode */
extern int wyse8bit;                    /* WYSE ASCII 8th bit quoting */
bool     keyclick  = FALSE ;
int      dec_upss = TX_8859_1 ;
int      dec_lang = VTL_NORTH_AM;       /* DEC VT Language = North American */
int      dec_nrc  = TX_ASCII;           /* DEC NRC for use during NRC Mode  */
int      dec_kbd  = TX_8859_1;          /* DEC Keyboard character set       */
bool     sound_playing = FALSE;         /* If a sound is playing */
/*
  Terminal parameters that can also be set externally by SET commands.
  Formerly they were declared and initialized here, and had different
  names, as shown in the comments.  Now they are declared and
  initialized in ckuus7.c.  - fdc
*/
int tt_kb_mode = KBM_EN ;               /* Keyboard is in English mode */
int tt_kb_glgr = FALSE;                 /* Kbd Follows GL/GR charset */
bool send_c1 = FALSE;                   /* Flag for sending C1 controls */
extern int send_c1_usr ;                /* User default for send_c1 */

/* When switching to the alternate screen, the page the terminal *was* on is
 * saved here so it can be restored when switching back. In the unlikely event
 * someone wants to use both VT paging and the xterm alternate screen at the
 * same time. */
int saved_view_page = -1;
int saved_cursor_page = -1;
int decspma_max_page = -1;  /* How many pages does the host want (DECSPMA) */
int user_pages = -1; /* How many pages does the user want (SET TERM PAGE COUNT) */

/* DRCS and Ruled Lines extensions only available in KUI builds */
#ifdef KUI
#define DRCS_EXT "7;"
#define EXT_RULED_LINES "43;"
#else
#define DRCS_EXT ""
#define EXT_RULED_LINES ""
#endif /* KUI */
#ifdef LATIN2
#define EXT_LATIN2 "42;"
#else
#define EXT_LATIN2 ""
#endif /* LATIN2 */

/*
  VT220 and higher Pn's for terminal ID string are (* = Not supported):
     1 - 132 columns
     2 - Printer port
  *  3 - ReGIS graphics
  *  4 - Sixel graphics
  *  5 - Katakana
     6 - DECSED - Selective erase
     7 - DRCS - Soft character sets   (KUI builds only)
     8 - UDK - User-defined keys
     9 - National Replacement Character Sets can be designated by host
  * 10 - Kanji
    11 - Status Display
  * 12 - Serbo-Croation (SCS)
  * 13 - Local editing
    14 - 8-bit Interface Architecture
    15 - Technical character set
  * 16 - Locator device port
  * 17 - Terminal State Interrogation
  * 18 - Windowing Capability
  * 19 - Dual sessions
  * 20 - APL
  * 21 - Horizontal Scrolling
    22 - Color
    23 - Greek
  * 24 - Turkish
  * 25 - Arabic Bilingual Mode 1
  * 26 - Arabic Milingual Mode 2
  * 27 - Arabic Milingual Mode 3
    28 - Rectangular Editing
  * 29 - ANSI Text Locator
  * 30 - Hanzi
    32 - Text Macros
  * 33 - Hangul and Hanja
  * 34 - Icelandic
  * 35 - Arabic Bilingual with Text Controls
  * 36 - Arabic Bilingual with no Text Controls
  * 37 - Thai
  * 38 - Character Outlining
  * 39 - Page Memory Extension
    42 - ISO Latin-2
    43 - Ruled Lines   (KUI builds only)
    44 - PC Term
    45 - Soft-key mapping
    46 - ASCII Terminal emulation
*/
/* RFC1091 (telnet terminal type option) recommends using the terminal types
 * from RFC1010. This has been obsoleted by the online database available at:
 *   https://www.iana.org/assignments/terminal-type-names/terminal-type-names.xhtml
 * though it doesn't appear to have been updated in a *very* long time; the
 * VT420 (released 1990) and VT520 (released 1993) are missing for example.
 */
/* Warning: Device Attribute Responses longer than 50 chars requires the
    sendescseq buffer to be enlarged */
struct tt_info_rec tt_info[] = {        /* Indexed by terminal type */
    "TTY", {NULL},                              "",                    /* Teletype */
    "D200", {"DG200","DATA-GENERAL-200",NULL},  "o#!J ",               /* Data General 200 */
    "D210", {"DG210","DATA-GENERAL-210",NULL},  "o#(HY",               /* Data General 210 */
    "D217", {"DG217","DATA-GENERAL-217",NULL},  "o#(HY",               /* Data General 217 */
    "HP2621", {"HP2621P","HP2621A","HP-2621",NULL},"2621A",            /* HP 2621A */
    "HPTERM", {"HP-TERM","X-HPTERM",NULL},      "X-hpterm",            /* HP TERM */
    "H1500", {"HZ1500","HAZELTINE-1500",NULL},  "",                    /* Hazeltine 1500 */
    "VC404", {"VOLKER-CRAIG-404",NULL},         "",                    /* Volker Craig VC4404/404 */
    "WY30", {"WYSE-30","WYSE30",NULL},          "30\r",                /* WYSE-30 */
    "WY50", {"WYSE-50","WYSE50",NULL},          "50\r",                /* WYSE-50 */
    "WY60", {"WYSE-60","WYSE60",NULL},          "60\r",                /* WYSE-60 */
    "WY160", {"WYSE-160","WYSE160",NULL},       "160\r",               /* WYSE-160 */
    "QNX",  {"QNX4",NULL},                      "",                    /* QNX */
    "QANSI", {NULL},                            "",                    /* QNX ANSI */
    "VT52",{"DEC-VT52",NULL},                   "/Z",                  /* DEC VT52 */
    "H19", {"HEATH","ZENITH","Z19",NULL},       "/K",                  /* Heath-19 */
    "IBM3151", {"I3151",NULL},                   "",                   /* IBM 3151 */
    "SCOANSI", {"SCO-ANSI","ANSI-850","ANSI-8859",NULL},    "",        /* SCO ANSI */
    "AT386",  {"386AT","ATT6386",NULL},         "",                    /* AT-386 */
    "ANSI",   {"DOSANSI","ANSI.SYS","PCANSI",NULL},"",                 /* "ANSI"  */
    "VIP7809", {NULL},                          "7813  P GC  A\003",   /* Honeywell MOD400 4.0 */
    "LINUX",  {NULL},                           "",                    /* Linux */
    "HFT", {"IBM8512","IBM8513",NULL},          "[?1;2c",              /* IBM HFT */
    "AIXTERM", {"AIXTERM-M",NULL},              "[?1;2c",              /* IBM AIXTERM */
    "SUN", {"SUN-COLOR",NULL},                  "",                    /* SUN Console */
    "BA80-08", {"BA80",NULL},                   "",                    /* Nixdorf BA80 */
    "BETERM",  {NULL},                          "",                    /* BEOS ANSI */
    "VT100", {"DEC-VT100","VT100-AM",NULL},     "[?1;2c",              /* DEC VT100 */
    "VT102", {"DEC-VT102",NULL},                "[?6c",                /* DEC VT102 */
    "VT220", {"DEC-VT220","DEC-VT200","VT200",NULL}, "[?62;1;2;6;"DRCS_EXT"8;9;15;44c",  /* DEC VT220 */
    "VT220PC", {"DEC-VT220-PC","DEC-VT200-PC","VT200PC",NULL}, "[?62;1;2;6;"DRCS_EXT"8;9;15;44c",  /* DEC VT220 w/ PC keyboard */
    "VT320", {"DEC-VT320","DEC-VT300","VT300",NULL}, "[?63;1;2;6;"DRCS_EXT"8;9;15;44c",  /* DEC VT320 */
    "VT320PC", {"DEC-VT320-PC","DEC-VT300-PC","VT300PC",NULL}, "[?63;1;2;6;"DRCS_EXT"8;9;15;44c",  /* DEC VT320 w/ PC keyboard */
    "WY370", {"WYSE-370","WYSE370","WY350",NULL},"[?63;1;2;6;"DRCS_EXT"8;9;15;44c",  /* WYSE 370 (same as VT320) */
    "97801", {"SNI-97801",NULL},                "[?62;1;2;6;8;9;15;44c",  /* Sinix 97801 */
    "AAA", { "ANNARBOR", "AMBASSADOR",NULL}, "11;00;00", /* Ann Arbor Ambassador */
#ifdef COMMENT
    "VT420", {"DEC-VT420","DEC-VT400","VT400",NULL},    "[?64;1;2;6;"DRCS_EXT"8;9;15;23;42;44;45;46c",       /* DEC VT420 */
    "VT525", {"DEC-VT525","DEC-VT500","VT500",NULL},    "[?65;1;2;6;"DRCS_EXT"8;9;15;22;23;42;44;45;46c",       /* DEC VT520 */
#endif /* COMMENT */
    "K95",    {"K95",NULL}, "[?63;1;2;6;"DRCS_EXT"8;9;15;21;22;28;32;"EXT_LATIN2""EXT_RULED_LINES"44c",     /* Kermit 95 self-personality */
            /* K95 Device Attributes:
				VT320;132-columns;printer;selective-erase;DRCS;user-defined-keys;
                national-replacement-character-sets;technical-characters;
				horizontal-scrolling;ansi-color;rectangular-editing;text-macros;
				latin-2;ruled-lines;PCTerm
            */
#undef EXT_RULED_LINES
#undef EXT_LATIN2
    "TVI910", {"TELEVIDEO-910","TVI910+""910",NULL},    "TVS 910 REV.I\r",        /* TVI 910+ */
    "TVI925", {"TELEVIDEO-925","925",NULL},     "TVS 925 REV.I\r",        /* TVI 925  */
    "TVI950", {"TELEVIDEO-950","950",NULL},     "1.0,0\r",                /* TVI 950  */
    "ADM3A",  {NULL}, "", /* LSI ADM 3A */
    "ADM5",   {NULL}, "", /* LSI ADM 5 */
    "VTNT",   {NULL},                           "",                       /* Microsoft NT VT */
    "REGENT25",{NULL},                           "",                    /* ADDS Regent 25 */
    "IBM3101",{"I3101",NULL},   ""                       /* IBM 31xx */
};
int max_tt = TT_MAX;                    /* Highest terminal type */

/* SET TERMINAL values ... */

extern int tt_arrow;                    /* Arrow-key mode */
extern int tt_keypad;                   /* Keypad mode */
extern int tt_shift_keypad;             /* Keypad Shift mode */
extern int tt_wrap;                     /* Autowrap */
extern int tt_type;                     /* Terminal type */
extern int tt_cursor_usr;               /* Cursor type */
extern int tt_cursorena_usr;            /* Cursor enabled by user */
extern int tt_cursor_blink;             /* Cursor blinks? */
extern int tt_cursor;                   /* Active cursor mode */
extern int tt_answer;                   /* Answerback enabled/disabled */
extern int tt_scrsize[];                /* Scrollback buffer size */
extern int tt_roll[];                   /* Scrollback style */
extern int tt_rows[];                   /* Screen rows */
extern int tt_cols[];                   /* Screen columns */
       int tt_cols_usr = 80;            /* User default screen width */
int tt_szchng[VNUM] = {1,1,1,0}; /* Screen Size Changed */
extern int cmd_rows;                    /* Screen rows */
extern int cmd_cols;                    /* Screen columns */
extern int tt_ctstmo;                   /* CTS timeout */
extern int tt_pacing;                   /* Output-pacing */
extern int tt_mouse;                    /* Mouse */
#ifdef KUI
extern int tt_scrollmode;               /* Terminal Scrolling Mode */
#endif /* KUI */
extern int tt_url_hilite;
extern int tt_url_hilite_attr;
int tt_type_vt52 = TT_VT52 ;            /* Terminal Type Mode before entering VT52 mode */
#ifdef KUI
#define SYNC_OUTPUT_TIMEOUT 1000
int 	 tt_sync_output = FALSE;
int      tt_sync_output_timeout = 0;
#endif /* KUI */
int      holdscreen = FALSE ;

int      escstate = ES_NORMAL;
int      escnext = 1;
int      esclast = 0;

int marginbell = FALSE, marginbellcol = 72 ;

extern int autoscroll ;                 /* WYSE ASCII Term AutoScroll Mode */
extern int writeprotect ;               /* WYSE ASCII WriteProtect Mode */
extern int protect ;                    /* WYSE ASCII Protect Mode */
extern int wysegraphics ;               /* WYSE ASCII Graphics Mode */
extern vtattrib WPattrib ;              /* WYSE ASCII WriteProtect Mode Attrib */
extern vtattrib defWPattrib ;           /* WYSE ASCII default WP Mode Attrib */
extern int attrmode ;                   /* WYSE ASCII Attribute Mode */
extern int wy_keymode ;                 /* WYSE ASCII Key Appl Mode */
extern int wy_enhanced ;                /* WYSE ASCII Enhanced Mode */
extern int wy_widthclr ;                /* WYSE ASCII Width Clear Mode */
extern int wy_autopage ;                /* WYSE ASCII Auto Page Mode */
extern int wy_monitor ;                 /* WYSE ASCII Monitor Mode */
extern int wy_nullsuppress;             /* WYSE ASCII Null Suppression */
extern int tvi_ic ;                     /* TVI insert character */
extern int wy_block;                    /* TVI block mode (FALSE = Conversation mode) */
extern int hzgraphics;                  /* Hazeltine graphics mode */

int tt_sac = SP;                        /* Spacing Attribute Character */
int sni_pagemode = FALSE;               /* 97801 Page Mode */
int sni_pagemode_usr = FALSE;           /* 97801 Page Mode (User Default) */
int sni_scroll_mode = FALSE;            /* 97801 Roll (power-on) or Scroll */
int sni_scroll_mode_usr = FALSE;        /* 97801 Roll or Scroll (User Default) */
int sni_chcode = TRUE;                  /* 97801 CH.CODE mode */
int sni_chcode_usr = TRUE;              /* 97801 CH.CODE mode */
int sni_chcode_7 = TRUE;                /* 97801 CH.CODE key enabled 7-bit mode */
int sni_chcode_8 = TRUE;                /* 97801 CH.CODE key enabled 8-bit mode */
int sni_bitmode = 8;                    /* 97801 CH.CODE 8-bit mode */
CHAR sni_kbd_firmware[7]="920031";      /* 97801 Keyboard Firmware Version */
CHAR sni_term_firmware[7]="830851";     /* 97801 Terminal Firmware Version */


#ifdef KUI
/* VT level 2 DRCS Support
 * ------------------------
 */
drcs_t *drcsbuf[DRCS_BUFFERS] = {NULL, NULL};
char decdlda = 2;

/* Replacement character glyphs */
#define DRCS_REPLACEMENT_VT220          0
#define DRCS_REPLACEMENT_VT320          1
#define DRCS_REPLACEMENT_VT525_80x27    2
#define DRCS_REPLACEMENT_VT525_80x43    3
#define DRCS_REPLACEMENT_VT525_80x54    4
#define DRCS_REPLACEMENT_VT525_132x27   5
#define DRCS_REPLACEMENT_VT525_132x43   6
#define DRCS_REPLACEMENT_VT525_132x54   7

static drcs_glyph_t replacement_characters[8] = {
    {   /* VT220 */
        {
            0x0000,	/* 0b0000000000000000 */
            0x7c00,	/* 0b0111110000000000 */
            0x8200,	/* 0b1000001000000000 */
            0x6000,	/* 0b0110000000000000 */
            0x1000,	/* 0b0001000000000000 */
            0x1000,	/* 0b0001000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x1000,	/* 0b0001000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    },
    {   /* VT320 */
        {
            0x0000,	/* 0b0000000000000000 */
            0x07e0,	/* 0b0000011111100000 */
            0x1ff8,	/* 0b0001111111111000 */
            0x3c3c,	/* 0b0011110000111100 */
            0x3c00,	/* 0b0011110000000000 */
            0x3c00,	/* 0b0011110000000000 */
            0x1fc0,	/* 0b0001111111000000 */
            0x07f0,	/* 0b0000011111110000 */
            0x00f0,	/* 0b0000000011110000 */
            0x0000,	/* 0b0000000000000000 */
            0x00f0,	/* 0b0000000011110000 */
            0x00f0,	/* 0b0000000011110000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    },
    {   /* VT525, 80x27 (10x16) */
        {
            0x3f00,	/* 0b0011111100000000 */
            0x7f80,	/* 0b0111111110000000 */
            0xffc0,	/* 0b1111111111000000 */
            0xe1c0,	/* 0b1110000111000000 */
            0xe1c0,	/* 0b1110000111000000 */
            0xe1c0,	/* 0b1110000111000000 */
            0xf000,	/* 0b1111000000000000 */
            0x7800,	/* 0b0111100000000000 */
            0x3c00,	/* 0b0011110000000000 */
            0x1c00,	/* 0b0001110000000000 */
            0x1c00,	/* 0b0001110000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x1c00,	/* 0b0001110000000000 */
            0x1c00,	/* 0b0001110000000000 */
            0x1c00,	/* 0b0001110000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    },
    {   /* VT525, 80x43 (10x10) */
        {
            0x3f00,	/* 0b0011111100000000 */
            0x7f80,	/* 0b0111111110000000 */
            0x6180,	/* 0b0110000110000000 */
            0x7180,	/* 0b0111000110000000 */
            0x3800,	/* 0b0011100000000000 */
            0x1c00,	/* 0b0001110000000000 */
            0x0c00,	/* 0b0000110000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0c00,	/* 0b0000110000000000 */
            0x0c00,	/* 0b0000110000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    },
    {   /* VT525, 80x54 (10x8) */
        {
            0x1f00,	/* 0b0001111100000000 */
            0x3180,	/* 0b0011000110000000 */
            0x3000,	/* 0b0011000000000000 */
            0x1c00,	/* 0b0001110000000000 */
            0x0600,	/* 0b0000011000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0600,	/* 0b0000011000000000 */
            0x0600,	/* 0b0000011000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    },
    {   /* VT525, 132x27 (6x16) */
        {
            0x0000,	/* 0b0000000000000000 */
            0x7800,	/* 0b0111100000000000 */
            0xfc00,	/* 0b1111110000000000 */
            0xcc00,	/* 0b1100110000000000 */
            0xcc00,	/* 0b1100110000000000 */
            0xc000,	/* 0b1100000000000000 */
            0xe000,	/* 0b1110000000000000 */
            0x7000,	/* 0b0111000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    },
    {   /* VT525, 132x43 (6x10) */
        {
            0x7800,	/* 0b0111100000000000 */
            0xfc00,	/* 0b1111110000000000 */
            0xcc00,	/* 0b1100110000000000 */
            0xc000,	/* 0b1100000000000000 */
            0x6000,	/* 0b0110000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    },
    {   /* VT525, 132x54 (6x8) */
        {
            0x7800,	/* 0b0111100000000000 */
            0xcc00,	/* 0b1100110000000000 */
            0x6000,	/* 0b0110000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x3000,	/* 0b0011000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000,	/* 0b0000000000000000 */
            0x0000 	/* 0b0000000000000000 */
        }, 1
    }
};

/* Erases a single rendition of a particular font buffer */
void
erase_font_buffer_rendition(drcs_rendition_t *drcs_rendition,
                            int rendition) {
    int i, glyph_id;

    if (drcs_rendition == NULL) return;

    debug(F101, "Erasing DRCS font rendition", 0, rendition);

    /* Figure out which replacement character to use */
    switch (tt_type) {
        case TT_VT220:
        case TT_VT220PC:
            glyph_id = DRCS_REPLACEMENT_VT220;
            break;
        case TT_VT320:
        case TT_VT320PC:
        case TT_WY370:
            /* TODO: 132 column glyph */
            glyph_id = DRCS_REPLACEMENT_VT320;
            break;
        case TT_VT420:
        case TT_VT520:
        case TT_VT525:
        case TT_K95:
        default: {
            drcs_rendition->width = 10;
            switch (rendition) {
                default:
                case DRCS_RENDITION_01_80x24:
                    glyph_id = DRCS_REPLACEMENT_VT525_80x27;
                    drcs_rendition->height = 16;
                    break;
                case DRCS_RENDITION_02_132_24:
                    glyph_id = DRCS_REPLACEMENT_VT525_132x27;
                    drcs_rendition->height = 16;
                    drcs_rendition->width = 6;
                    break;
                case DRCS_RENDITION_11_80x36:
                    glyph_id = DRCS_REPLACEMENT_VT525_80x43;
                    drcs_rendition->height = 10;
                    break;
                case DRCS_RENDITION_12_132x36:
                    glyph_id = DRCS_REPLACEMENT_VT525_132x43;
                    drcs_rendition->height = 10;
                    drcs_rendition->width = 6;
                    break;
                case DRCS_RENDITION_21_80x48:
                    glyph_id = DRCS_REPLACEMENT_VT525_80x54;
                    drcs_rendition->height = 8;
                    break;
                case DRCS_RENDITION_22_132x48:
                    glyph_id = DRCS_REPLACEMENT_VT525_132x54;
                    drcs_rendition->height = 8;
                    drcs_rendition->width = 6;
                    break;
            }
            break;
        }
    }

    /* The renderer needs to know how big the replacement glyphs are... */
    drcs_rendition->cell_width = drcs_rendition->width;
    drcs_rendition->cell_height = drcs_rendition->height;
    drcs_rendition->undefined = TRUE;

    for (i = 0; i < 96; i++) {
        drcs_rendition->glyphs[i] = replacement_characters[glyph_id];
    }
}

/* Erases all renditions for a particular font buffer */
void
erase_font_buffer(drcs_t *drcs) {
    int i;

    if (drcs == NULL) return;

    debug(F100, "Erasing DRCS font buffer", 0, 0);

    for (i = 0; i < DRCS_RENDITIONS_TOTAL; i++) {
        erase_font_buffer_rendition(
            drcs->renditions[i],
            i);
    }
}

void
decdld(int font_number, int starting_character, int erase_control,
       int width, int font_set_size, int usage, int height,
       int character_set_size, const char* definition, int length) {
    drcs_t *drcs;
    int i=0, j=0, start=0;
    int max_font_buffers;
    int cell_height, cell_width, max_width, used_height = 0;
    int h_offset = 0, v_offset = 0;
    int lines = 24, columns = 80;
    BOOL is_132cols = FALSE, is_full_cell = FALSE, is_vt220_font = FALSE;
    BOOL is_36_line = FALSE, is_48_line = FALSE;
    BOOL default_height = FALSE, default_width = FALSE, erased = FALSE;
    int glyph = 0, row = 0, column = 0;
    char name[4] = {0, 0, 0, 0};
    int rendition = DRCS_RENDITION_01_80x24;
    int erase_rendition = rendition;
    int name_max_len = 0;

    /* TODO:  VTStars behaviour has not been fully characterised and full
     *        testing will be required if that is ever offered as a terminal
     *        type. But here are some notes based on observations:
     *          - /Seems/ to treat all fonts as full-cell
     *          - Doesn't leave a gap on the left for text fonts
     *          - Undefined behaviour hasn't been tested at all.
     *          - It generally seems quite buggy. Glyphs seem to start out with
     *              random garbage in them (memory not erased?), you have to
     *              spam it with something like SGR after sending a DECDLD or it
     *              gets stuck, result of switching to DECCOLM is odd
     *          - Only supports 80 column and 132 column fonts
     */

    debug(F100, "DECDLD", "", 0);

    /* Note that we use tt_type rather than tt_type_mode here as DRCS behaviour
     * depends on the terminal K95 is emulating, not the terminal the emulated
     * terminal is emulating (DECTME, DECSCL, etc). Not that any VT seems to let
     * you emulate a VT220...VT420.
     */

    /* VT220, 420 and 520 only allow two intermediates and a final. STD-070
     * allows three intermediates and a final */
    name_max_len = tt_type == TT_K95 ? 4 : 3;

    is_132cols = font_set_size == 2 || font_set_size == 12 ||
        font_set_size == 22;
    is_36_line = font_set_size == 11 || font_set_size == 12;
    is_48_line = font_set_size == 21 || font_set_size == 22;
    is_full_cell = usage == 2;

    /* Figure out how many font buffers we should allow access to based on
     * current terminal emulation. No DEC terminals support more than two, but
     * their printers all support at least 3 if they support any at all.
     * */
    switch (tt_type) {
        case TT_VT220:
        case TT_VT220PC:
        case TT_VT320:     /* The VT300 and VT420 actually have two - one for */
        case TT_VT320PC:   /* each session. So from the hosts POV, only one  */
        case TT_VT420:
        case TT_WY370:
            max_font_buffers = 1;
            break;
            /*case TT_VT510:*/
        case TT_VT520:
            max_font_buffers = decdlda;
            break;
        case TT_VT525:
        case TT_K95:
            max_font_buffers = 2;
            break;
        default:
            debug(F111, "DECDLD", "End - Not supported by terminal type", tt_type);
            return; /* DECDLD not supported by this terminal type */
    }

    /* And max cell dimensions */
    switch (tt_type) {
        case TT_VT220:
        case TT_VT220PC:
            cell_height = 10;
            cell_width = 10;
            max_width = 8;  /* Columns 9 and 10 are copies of 8 */
            /* DECCOLM doesn't affect the cell width (at least not the
             * addressable portion) - it primarily seems to result in narrower
             * pixels. */
            break;
        case TT_VT320:
        case TT_VT320PC:
            /* Specs on page 90 of EK-VT320-UU */
            cell_height = 12;
            cell_width = is_132cols ? 9 : 15;
            max_width = cell_width;  /* full cell */
            if (!is_full_cell) { /* text cell */
                max_width = is_132cols ? 7 : 12;
            }

            break;
        case TT_VT340:
            cell_width = is_132cols ? 6 : 10;
            max_width = cell_width;  /* full cell */
            if (!is_full_cell) { /* text cell */
                max_width = is_132cols ? 5 : 9;
            }
            cell_height = 20;  /* The docs say so, but it feels wrong */
            break;
        case TT_WY370:
            /* The WY-370 apparently supports a 161 column and 52 line modes,
             * but it doesn't have different font set size parameters for them.
             * Like the VT520 it just has a wide and a narrow font, and you
             * have to handle switching fonts for different heights yourself.
             * And for 132 vs 161 columns I guess its the same - you have to
             * track which mode you're in and send the right font.
             */

            cell_width = is_132cols ? 10 : 16;
            max_width = cell_width;  /* full cell */
            if (!is_full_cell) { /* text cell */
                /* 161 column display also uses a width of 7 */
                max_width = is_132cols ? 7 : 12;
            }
            cell_height = 16;
            break;
        case TT_VT420:  /* VT420 and up all have the same cell dimensions */
        /*case TT_VT510:*/
        case TT_VT520:
        case TT_VT525:
        case TT_VTSTAR:
        case TT_K95:
        default:
            cell_width = is_132cols ? 6 : 10;
            max_width = cell_width; /* full cell */
            if (!is_full_cell) { /* text cell */
                /* While the manual says the maximum widths are 6 and 9, the
                 * terminal rejects these - the actual implemented maximum is
                 * 5 and 8. */
                max_width = is_132cols ? 5 : 8;
            }
            cell_height = 16;
            if (is_36_line) cell_height = 10;
            if (is_48_line) cell_height = 8;
            break;
    }

    /******* Validate Parameters *******/
    /* Which are:
     *  Pfn ; Pcn ; Pe ; Pcmw ; Pss ; Pu ; Pcmh ; Pcss
     * Printers use:
     *  Pfn ; Pcn ; Pe ; Pcmw ; Pss ; Pu ; Pcmh ; Pcss ; Psgr
     */

    /* Pfn - font number */
    if (font_number > max_font_buffers) {
        debug(F111, "DECDLD", "End - invalid font number", font_number);
        return;
    }


    /* Pcn - Starting Character
     * This defines the first glyph we're expecting to receive */
    if (starting_character > (character_set_size == 1 ? 95 : 93)) {
        debug(F111, "DECDLD", "End - invalid starting character", starting_character);
        return;
    }
    glyph = starting_character;

    /* Pe - Erase Control
     * One of three values:
     *     0 - erase everything
     *     1 - erase only characters being reloaded
     *     2 - erase all renditions (normal, bold, 80-column, 132-column)
     * The VT220 docs say this erases all font buffers, but it only has one so
     * that's probably meaningless
     */
    if (erase_control > 2) {
        debug(F111, "DECDLD", "End - invalid erase control", erase_control);
        return;
    }

    /* Pcmw - Character Matrix Width
     * One of these values:
     *     0 - Default
     *          VT220: 7x10
     *          VT420: 10 wide for 80 columns, 6 wide for 132 columns
     *     1 -  VT220: Not used/Illegal
     *     2 -  VT220 compatible: 5 wide, 10 high
     *     3 -  VT220 compatible: 6 wide, 10 high
     *     4 -  VT220 compatible: 7 wide, 10 high
     *     5...16: Character matrix width.
     *       EK-VT320-UU says values up to 15.
     *       EK-VT3XX-TP says values up to 10
     *       EK-VT420-RM says "must be less than 10. Any Pcmw value over 10 is illegal"
     *       EK-VT510-RM says values up to 10
     *       EK-VT520-RM says values up to 10
     *       WY-370 supports up to 16 wide
     * For the VT510, if Pu != 2, then the limits are:
     *    9 wide for 80 columns
     *    6 wide for 132 columns
     * VT52x seems to be the same.
     *
     * The VT220 doesn't constrain glyphs to this size - even if a width of 5
     * specified (Pcmw=2), you can still define glyphs up to 8 wide, though the
     * 8th column is doubled.
     * */
    switch (width) {
        case 0:
            default_width = TRUE;
            if (ISVT320(tt_type))
                width = max_width;
            else
                width = 7;
            break;
        case 1:
            return; /* Illegal */
        case 2:
            is_vt220_font = TRUE;
            width = 5; height = 10; break;
        case 3:
            is_vt220_font = TRUE;
            width = 6; height = 10; break;
        case 4:
            is_vt220_font = TRUE;
            width = 7; height = 10; break;
        default:
            if (width > max_width) {
                debug(F111, "DECDLD", "End - invalid width", width);
                debug(F111, "DECDLD", "Note - max width", max_width);
                return;
            }
            /* Arbitrary widths are only supported by the VT320 and up */
            if (!ISVT320(tt_type)) {
                debug(F111, "DECDLD", "End - invalid width for VT220", width);
                return;
            }
            break;
    }

    /* Pss - Font Set Size. VT220 calls this Pw.
     *     0 - default (80 columns, 24 lines)
     *     1 - 80 columns, 24 lines
     *     2 - 132 columns, 24 lines
     *    11 - 80 columns, 36 lines   (VT420 & VT510 only)
     *    12 - 132 columns, 36 lines  (VT420 & VT510 only)
     *    21 - 80 columns, 48 lines   (VT420 & VT510 only)
     *    22 - 132 columns, 48 lines  (VT420 & VT510 only)
     *
     * VT420 supports six renditions per font:
     *   80 columns, 24/36/48 lines
     *   132 columns, 24/36/48 lines
     * The VT5xx only supports two: 80columns or 132columns
     */
    switch (font_set_size) {
        case 0:
        case 1: {
            rendition = DRCS_RENDITION_01_80x24;
            break;
        }
        case 2:  if ISVT320(tt_type) {
            rendition = DRCS_RENDITION_02_132_24;
            break;
        } else {
            /* VT220 doesn't switch fonts for DECCOLM */
            rendition = DRCS_RENDITION_01_80x24;
            break;
        }
        case 11: if ISVT420(tt_type) {
            rendition = DRCS_RENDITION_11_80x36;
            break;
        }
        case 12: if ISVT420(tt_type) {
            rendition = DRCS_RENDITION_12_132x36;
            break;
        }
        case 21: if ISVT420(tt_type) {
            rendition = DRCS_RENDITION_21_80x48;
            break;
        }
        case 22: if ISVT420(tt_type) {
            rendition = DRCS_RENDITION_22_132x48;
            break;
        }
        default: {
            debug(F111, "DECDLD", "End - invalid font set size", font_set_size);
            return; /* Invalid */
        }
    }
    erase_rendition = rendition;
    if (tt_type_mode == TT_VT520 || tt_type_mode == TT_VT525) {
        /* The VT520 (v2.1) doesn't switch fonts for different screen heights.
         * It only has slots for a single 80 column rendition and a single
         * 132 column rendition, and it uses those two renditions for all screen
         * heights. Loading an 80x24 font then switching to an 80x48 screen
         * won't result in reverse question-marks - it seems to just truncate
         * glyphs to fit.
         *
         * TODO: Does the VT525 behave the same? It has more memory, so it
         *       *could* behave as the VT420 does.
         *
         * TODO: This still isn't *quite* right for VT520:
         *      - Loading an 80x24 font, then a 132x24 font. Now if you load a
         *          80x36 font it seems to wipe the 132x24 rendition for some
         *          reason. Loading an 80x24 font after a 132x24 font doesn't
         *          seem to produce the same behaviour.
         *      Further tests will need to be done to properly determine exact
         *      behaviour. It would be interesting to test other firmware
         *      versions as the observed behaviour seems kind of odd.
         */
        switch (rendition) {
            case DRCS_RENDITION_01_80x24:
            case DRCS_RENDITION_11_80x36:
            case DRCS_RENDITION_21_80x48:
            default:
                rendition = DRCS_RENDITION_01_80x24;
                break;
            case DRCS_RENDITION_02_132_24:
            case DRCS_RENDITION_12_132x36:
            case DRCS_RENDITION_22_132x48:
                rendition = DRCS_RENDITION_02_132_24;
                break;
        }
    }

    /* Pu - Font Usage. VT220 and VT510 calls this Pt.
     *     0 - default (text)
     *     1 - text
     *     2 - full-cell (Not supported on VT220)
     * */
    if (usage > 2) {
        debug(F111, "DECDLD", "End - invalid font usage", usage);
        return;
    }
    if (!ISVT320(tt_type) && is_full_cell) {
        debug(F110, "DECDLD", "End - full cell not supported for VT220 ", 0);
        return;
    }

    if (ISVT320(tt_type) && !is_vt220_font) {
        /* Pcmh - Character Cell Matrix height - VT320+
         * This is ignored (set to 10) if Pcmw is 2, 3 or 4.
         * VT320: 1-12, 0=12
         * VT340: 1-20, 0=20, >20 is illegal
         * VT420: 1-16, 0=16, >16 is illegal
         * VT5xx: 1-16, 0=16, >16 is illegal
         * */

        if (height > cell_height) {
            debug(F111, "DECDLD", "End - invalid height", height);
            debug(F111, "DECDLD", "Note - max height", cell_height);
            return;
        }
        if (height == 0) {
            default_height = TRUE;
            height = cell_height;
        }

        /* Pcss - Character Set Size - VT320+
         *     0 - 94-character set
         *     1 - 96-character set
         * */
        if (character_set_size > 1) {
            debug(F111, "DECDLD", "End - invalid character set size",
                character_set_size);
            return;
        }
    } else {
        /* VT220 */
        height = 10;
        character_set_size = 0;
        is_vt220_font = TRUE;
    }

    /* Dscs - the name for the soft character set
     * 0-3 intermediate characters, followed by a final character.
     */
    if (length < 1) {
        debug(F110, "DECDLD", "End - no character set name", 0);
        return;
    }
    for (start = 0; start <= name_max_len && start <= length; start++) {
        name[start] = definition[start];
        if (start == 4) {
            debug(F110, "DECDLD",
                "End - didn't get a final character for character set name", 0);
            return; /* Didn't get a final character in 0...2 */
        }
        if (definition[start] >= ' ' && definition[start] <= '/' &&
            start <= name_max_len-1) {
            continue;  /* Intermediate character */
        }
        if (definition[start] >= '0' && definition[start] <= '~') {
            break; /* Final character */
        }
        debug(F111, "DECDLD", "End - invalid character in character set name",
            definition[start]);
        return; /* Something invalid */
    }

    /* if we got this far, then the parameters are all valid and we can proceed
     * with loading the font. */

    /* Now figure out what the real dimensions should be. */

    EnterDRCSBufferCriticalSection();

    /* Decide which font buffer we're going to use */
    if (font_number == 0) {
        /* For the VT510 and up, 0 is supposed to mean the first empty
         * buffer, or buffer 1 if they're all populated. But the VT520 v2.1
         * actually behaves the same as all terminals: 0 means 1.
         */
        font_number = 1;
    }
    font_number -= 1;

    if (drcsbuf[font_number] == NULL) {
        int i;
        debug(F101, "DECDLD allocating and pre-erasing font buffer", 0, font_number);
        drcs = (drcs_t*)malloc(sizeof(drcs_t));
        memset((void*)drcs, 0, sizeof(drcs_t));

        for (i = 0; i < DRCS_RENDITIONS_TOTAL; i++) {
            drcs->renditions[i] = (drcs_rendition_t*)malloc(
                sizeof(drcs_rendition_t));
            memset((void*)drcs->renditions[i], 0, sizeof(drcs_rendition_t));
            drcs->renditions[i]->rendition_id = i;
        }
        drcsbuf[font_number] = drcs;
        erase_font_buffer(drcs);
    } else {
        drcs = drcsbuf[font_number];
        if (drcs->renditions[rendition]->full_cell != is_full_cell ||
            drcs->renditions[rendition]->width != width ||
            drcs->renditions[rendition]->height != height ) {
            /* STD 070: "Changes to this {the full cell, character cell matrix
             * width or height} parameter since the last DECDLD sequence to this
             * buffer will result in the erasure of the entire set, and cause a
             * new load to start" */

            debug(F100, "DECDLD forcing erase control to 0 because one of these changed...", 0 , 0);
            debug(F111, "   old", "full-cell", drcs->renditions[rendition]->full_cell);
            debug(F111, "   new", "full-cell", is_full_cell);
            debug(F111, "   old", "width", drcs->renditions[rendition]->width);
            debug(F111, "   new", "width", width);
            debug(F111, "   old", "height", drcs->renditions[rendition]->height);
            debug(F111, "   new", "height", height);

            erase_control = 0;
        }
        if (drcs->is_96_chars != (character_set_size == 1)) {
            /* On the VT420, changing the size of the character set erases all
             * renditions of it */
            debug(F100, "DECDLD erasing entire font buffer because character set size changed", 0 , 0);
            erase_font_buffer(drcs);
        }
    }

    if (erase_control == 0) {
        /* Erase target font buffer only. STD-070 says it should erase *all*
         * charcters in the specified font buffer, but the VT420 and VT520 only
         * erase all characters in the *specified rendition* of the specified
         * font buffer. */
        debug(F101, "DECDLD Erase Rendition", 0, rendition);
        debug(F101, "DECDLD For Buffer", 0, font_number);
        erase_font_buffer_rendition(drcs->renditions[rendition], erase_rendition);
    } else if (erase_control == 2) {
        int i;
        debug(F101, "DECDLD Erase All Renditions for all buffers", 0, font_number);
        for (i = 0; i < DRCS_BUFFERS; i++) {
            if (drcsbuf[i] != NULL) {
                erase_font_buffer(drcsbuf[i]);
            }
        }
    } /* Else we'll erase glyphs as they're defined */

    drcs->name[0] = name[0];
    drcs->name[1] = name[1];
    drcs->name[2] = name[2];
    drcs->name[3] = name[3];
    drcs->name[4] = 0;
    drcs->renditions[rendition]->cell_width = cell_width;
    drcs->renditions[rendition]->cell_height = cell_height;
    drcs->renditions[rendition]->width = width;
    drcs->renditions[rendition]->height = height;
    drcs->renditions[rendition]->full_cell = is_full_cell;
    drcs->renditions[rendition]->undefined = FALSE;
    drcs->is_96_chars = character_set_size == 1;
    drcs->render_hints = DRCS_RENDER_HINT_NONE;

    if (is_vt220_font && !ISVT320(tt_type)) drcs->render_hints =
        DRCS_RENDER_HINT_VT220 | DRCS_RENDER_HINT_VT220_TEXT;

    /* Center text glyphs within the cell. The VT220 does not do this - at least
     * not in a normal way; its behaviour really has to be dealt with at render
     * time. */
    if (!is_full_cell) {
        switch (tt_type) {
            case TT_VT220:
            case TT_VT220PC:
                /* VT220 behaviour handled at render time */
                h_offset = 0;
                v_offset = 0;
                break;
            case TT_VT320:
            case TT_VT320PC:
            case TT_WY370:
                /* EK-VT320-UU says two pixels before the glyph and one after
                 * for 80 columns and one pixel before for 132 columns. */
                /* WY-370 Programmers Manual, 881133-02 Rev. A, June 1990,
                 * Page 4-9 (53) */
                h_offset = is_132cols ? 1 : 2;
                v_offset = 0;
                break;
            case TT_VT420:
                h_offset = 1;
                v_offset = 0;
                break;
            case TT_VTSTAR:
            /*case TT_VT510:*/
            case TT_VT520:
            case TT_VT525:
                /* The VT520 (v2.1) doesn't do any font centering at all.
                 * And VTStar doesn't seem to either */
                h_offset = 0;
                v_offset = 0;
                break;
            default:
            case TT_K95: {
                /* As all the DEC terminals seem to do something different, for
                 * K95 we'll center properly. */
                int hspace = cell_width - width;
                int vspace = cell_height - height;
                h_offset = hspace/2;
                v_offset = vspace/2;
            }

        }
    }

    debug(F100, "DECDLD Loading with these settings...", "", 0);
    debug(F101, "DECDLD Font Buffer", 0, font_number);
    debug(F110, "DECDLD Name", drcs->name, 0);
    debug(F101, "DECDLD Rendition", 0, rendition);
    debug(F101, "DECDLD Cell Width", 0, cell_width);
    debug(F101, "DECDLD Cell Height", 0, cell_height);
    debug(F101, "DECDLD Width", 0, width);
    debug(F101, "DECDLD Height", 0, height);
    debug(F101, "DECDLD Is Full Cell", 0, is_full_cell);
    debug(F101, "DECDLD Is 96 chars", 0, drcs->is_96_chars);
    debug(F101, "DECDLD Render Hits", 0, drcs->render_hints);
    debug(F101, "DECDLD H-Offset", 0, h_offset);
    debug(F101, "DECDLD V-Offset", 0, v_offset);

    for (i=start+1; i <= length; i++) {
        char sixel = definition[i];
        char bits;
        int bit;

        if (!erased) {
            for (j = 0; j < DRCS_MAX_CELL_HEIGHT; j++) {
                drcs->renditions[rendition]->glyphs[glyph].pixels[j] = 0;
            }
            drcs->renditions[rendition]->glyphs[glyph].undefined = FALSE;
            erased = TRUE;

            /* To ensure that the next character after the end of the sixel
             * string gets erased (this is what the VT420 and VT520 do) */
            if (i == length)
                break;
        }

        if (sixel >= BS && sixel <= CK_CR) {
            /* STD070: Bit combinations 0/8 (BS) to 0/13 (CR) may be included in
             * the command string and have no effect on the interpretation of
             * the data */
            continue;
        }

        /***********************************
         * The following are undefined behaviour per STD-070. The actions are
         * STD-070s recommended behaviour. */
        if (sixel >= 0xA1 && sixel <= 0xFE) {
            /* STD-070: 10/1 to 15/14 undefined behaviour, recommended
             * interpret as 2/1 to 7/14 */
            sixel &= 0x7F; /* Clear 7th bit */
        }
        if (((sixel >= NUL && sixel <= BEL) || (sixel >= SO && sixel <= US)) &&
            sixel != ESC) {
            /* STD070: Bit combinations 0/0 through 0/7 and 0/14 through 1/15
             * except for 1/11 (ESC) are undefined behaviour. Recommended to
             * ignore */

            /* VT220, VT420, VT520: 0x13 seems to get the terminal stuck,
             * requiring clear comms to get it working again.*/

            /* The VT220, VT420 and VT520 cancel the DECDLD if they receive a
             * CAN or a SUB leaving the font partially downloaded. For SUB, the
             * VT220 and 420 additionally output a reverse question mark while
             * the VT520 seems to glitch. The area above the titlebar where the
             * session icons live is briefly replaced with garbage from
             * somewhere in memory and NUL is written to the terminal screen
             * while the rest of the DECDLD sequence disappears. We don't
             * implement /that/ behaviour here.
             *
             * Partial processing of the DECDLD as per the hardware terminals is
             * special cased over in cwrite() which will hand a canceled DCS
             * string off for processing if it looks like a DECDLD>
             */
            continue;
        }
        if (sixel == SP || sixel == DEL) {
            /* STD-070: 2/0 and 7/15 undefined behaviour, recommended ignore */
            continue;
        }
        if ((sixel >= '!' && sixel <= '>') && sixel != '/' && sixel != ';') {
            /* STD-070: 2/1 to 3/14 (excluding 2/15 and 3/11) undefined
             * behaviour, recommended ignore */
            continue;
        }
        if ((sixel >= 0x80 && sixel <= 0x9F) && sixel != 0x9C) {
            /* STD-070: C1 controls 8/10 to 9/15 (excl 9/12 ST) undefined
             * behaviour, recommended abort
             *
             * For most of these we won't get here - thet escape-sequence state
             * table will catch and handle them, dispatching the DCS sequence
             * specially if it looks like the DCString contains a DECDLD.
             */

            /* The VT220 ignores 0x80, VT420/520 don't */
            if (sixel > 0x80 || (tt_type != TT_VT220 && tt_type != TT_VT220PC)) {
                debug(F111, "DECDLD",
                    "End - character 0x80-0x9F (excl 0x9C) in sixel string",
                    sixel);
                break;
            }
        }
        if (sixel == 0xA0 || sixel == 0xFF) {
            /* STD-070: 10/0 and 15/15 undefined behaviour, recommended
             * ignore */
            continue;
        }
        /* End of undefined behaviour handling
         ************************************/

        if (sixel == ';') {
            /* ';' means next glyph */

            if ((drcs->render_hints & DRCS_RENDER_HINT_VT220_TEXT) &&
                    (tt_type == TT_VT220 || tt_type == TT_VT220PC)) {
                if (column >= 8) {
                    /* The 8th column is stretched to three pixels to join up
                     * with the next cell, so text fonts will never put anything
                     * in that column. If one or more glyphs leave that column
                     * out, we'll treat it as a text font and handle centering
                     * at render time. */
                    drcs->render_hints = drcs->render_hints & ~DRCS_RENDER_HINT_VT220_TEXT;
                }
            }

            glyph++;
            erased = FALSE;
            row = 0;
            column = 0;
            continue;
        }
        if (sixel == '/') {
            /* '/' means next row of sixels */
            row +=6; /* Each sixel spans six rows */
            column = 0;
            continue;
        }

        /* Ignore sixel if it is outside the specified size
         * The VT220 is a bit odd; its cells are 10 wide, only 8 columns are
         * addressable and it allows all 8 columns to be filled even if the font
         * specifies a smaller width.
         *
         * Note, column here is zero-based, while width is not.*/
        if (ISVT320(tt_type) && column >= width) continue;
        if (!ISVT320(tt_type) && column >= 8) continue;
        if (column >= max_width || column >= cell_width) continue;

        /* Ignore entire glyph if we're trying to load a 94-character set
         * starting at position 0, or a position past the range for the
         * character set size */
        if (character_set_size == 0) {
            if (glyph == 0 || glyph > 94 ) continue;
        }
        else if (glyph > 95) continue;

        bits = sixel - '?';

        for (bit = 0; bit < 6; bit++) {
            /* Only the VT520 crops glyphs to the specified height - the rest
             * will draw as much as you give them regardless of the height
             * specified. */
            if (row+bit > height && ISVT520(tt_type)) continue;

            if (bits & (1 << bit)) {
                int r = row + bit + v_offset;
                drcs->renditions[rendition]->glyphs[glyph].pixels[r] =
                    drcs->renditions[rendition]->glyphs[glyph].pixels[r]
                        | 0x8000 >> (column+h_offset);
                if (row+bit > used_height) used_height = row+bit;
            }
        }
        column++;
    }

    /* mark the font buffer as changed */
    drcs->serial++;
    debug(F101, "DECDLD Serial", 0, drcs->serial);
    debug(F101, "DECDLD Glyphs Loaded", 0, glyph);

    LeaveDRCSBufferCriticalSection();

    /* mark the vscreen as dirty */
    VscrnIsDirty(VTERM);
    debug(F110, "DECDLD", "Finished", 0);
}
#endif /* KUI */

/* VT level 4 Macro Support
 * ------------------------
 * Both the VT420 (EK-VT420-RM.002) and VT520 (EK-VT520-RM.A01) manuals claim
 * there is 6KB of space for storing macros ("The VT520 has 6 Kbytes of memory
 * available for the storage of macros"). While I believe this number is
 * probably true for the VT420, testing on my VT520 (FW v2.1) indicates it
 * actually has 10KB of macro space. For the K95 terminal type, the limit is
 * arbitrarily set at a nice round 256KB for now, but could be easily lifted
 * higher if there is ever a need. Perhaps it could even be made a settable
 * option (SET TERM MACRO-LIMIT?)
 *
 * The VT520 (in FW v2.1 at least, perhaps all versions) also treats tail calls
 * specially - these aren't pushed on to the stack, instead reusing the calling
 * macros stack entry. On my VT520, this *does* allow for creating infinite
 * loops which we do not emulate here. Instead, we only allow tail calls up to
 * the arbitrary limit specified in MACRO_CALL_DEPTH_LIMIT, after that they're
 * forced on to the stack which will protect against infinite loops as it does
 * with non-tail-calls.
 */
#define MACRO_SIZE_LIMIT_VT420 0x01800 	/* 6KB for the VT420 */
#define MACRO_SIZE_LIMIT_VT520 0x02800  /* 10KB for the VT520 */
#define MACRO_SIZE_LIMIT_K95   0x40000  /* 256KB for K95 */
#define MACRO_SIZE_LIMIT(tt) (ISK95((tt)) \
	? MACRO_SIZE_LIMIT_K95 \
	: ISVT520((tt)) \
		? MACRO_SIZE_LIMIT_VT520 \
		: MACRO_SIZE_LIMIT_VT420)
#define MACRO_CALL_DEPTH_LIMIT 256      /* Limit for vt_macro_call_depth */
#define MACRO_STACK_SIZE 16
bool vt_macro_invocation = FALSE;		/* Currently executing a macro? */
bool vt_macro_hard_reset = FALSE;		/* Terminal was hard reset, clear macros */
/* Stack and stack pointer - calls up to 16 levels deep as standard */
signed char vt_macro_stack[MACRO_STACK_SIZE] = {-1, -1, -1, -1, -1, -1, -1, -1};
signed char vt_macro_sp = -1;
/* Current position in a macro */
int vt_macro_position[MACRO_STACK_SIZE] = {-1, -1, -1, -1, -1, -1, -1, -1};
signed short vt_macro_call_depth = -1;  /* To stop infinite loops from tail calls */
unsigned int vt_macro_size=0;   		/* length of all macro definitions */
char* vt_macro_definitions[64] = {      /* And the macro definitions themselves */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void vt_macro_reset();		/* Halts macro execution and resets the stack, etc */
void vt_macro_clear();		/* Calls vt_macro_reset(), then clears all definitions */
/* ------------------------*/

/* Escape-sequence processing buffer */

unsigned short escbuffer[ESCBUFLEN+1];

/*
   For pushing back input characters,
   e.g. converting 8-bit controls to 7-bit escape sequences.
*/
static int f_pushed = 0, c_pushed = 0, f_popped = 0;

int sgrcolors = TRUE;                   /* Process SGR Color Commands */

int decstglt = DECSTGLT_COLOR;

/* These only apply to decstgly == DECSTGLT_ALTERNATE.
 * TODO: Does a real VT525 default these to ON or OFF?
 * If we have to deault these */
int decatcbm = FALSE;        /* True blink as well as blink color */
int decatcum = FALSE;        /* True underline as well as underline color */

int colorpalette = CK_DEFAULT_PALETTE;  /* Color palette to use */
int savedcolorpalette = CK_DEFAULT_PALETTE;

/* Copies of the RGB tables so that resetting the terminal can reset the
 * the colour palettes. */
ULONG SavedRGBTable256[256];
ULONG SavedRGBTable88[88];
ULONG SavedRGBTable[16];
#ifdef CK_PALETTE_WY370
ULONG SavedWY370RGBTable[65];
#endif /* CK_PALETTE_WY370 */
ULONG SavedVT525RGBTable[16];
ULONG SavedVT525MonoRGBTable[16];
ULONG SavedVT525ATCRGBTable[16];

/* The Wyse WY370 65-color palette.
 * The first 16 colors are *NOT* ANSI/AIXTERM-compatible!
 * TODO: Get color values for all of these! The manual only gives names.
 *
 * NOTE! These values aren't RGB, they're COLORREF - 0x00bbggrr (ugh)
 */
#ifdef CK_PALETTE_WY370
ULONG WY370RGBTable[65] = {
    0x000000,  /*  0 - Default                      /   /    */
    0x000000,  /*  1 - Black                      00/ 00/ 00 */
    0x000000,  /*  2 - Dark blue                    /   /    */
    0x000000,  /*  3 - Deep blue                    /   /    */
    0x000000,  /*  4 - Blue                         /   /    */
    0x000000,  /*  5 - Grass green                  /   /    */
    0x000000,  /*  6 - Teal blue                    /   /    */
    0x000000,  /*  7 - Electric blue                /   /    */
    0x000000,  /*  8 - Bright blue                  /   /    */
    0x000000,  /*  9 - Bright green                 /   /    */
    0x000000,  /* 10 - Light blue-green             /   /    */
    0x000000,  /* 11 - Turquoise                    /   /    */
    0x000000,  /* 12 - Sky blue                     /   /    */
    0x000000,  /* 13 - Green                        /   /    */
    0x000000,  /* 14 - Sea green                    /   /    */
    0x000000,  /* 15 - Blue-green                   /   /    */
    0x000000,  /* 16 - Cyan                         /   /    */
    0x000000,  /* 17 - Brick red                    /   /    */
    0x000000,  /* 18 - Violet                       /   /    */
    0x000000,  /* 19 - Indigio                      /   /    */
    0x000000,  /* 20 - Blue-purple                  /   /    */
    0x000000,  /* 21 - Khaki-green                  /   /    */
    0x000000,  /* 22 - Charcoal gray                /   /    */
    0x000000,  /* 23 - Powder blue                  /   /    */
    0x000000,  /* 24 - Medium blue                  /   /    */
    0x000000,  /* 25 - Medium green                 /   /    */
    0x000000,  /* 26 - Green-blue                   /   /    */
    0x000000,  /* 27 - Blue-gray                    /   /    */
    0x000000,  /* 28 - Light blue                   /   /    */
    0x000000,  /* 29 - Lime green                   /   /    */
    0x000000,  /* 30 - Seafoam green                /   /    */
    0x000000,  /* 31 - Pale blue-green              /   /    */
    0x000000,  /* 32 - Light cyan                   /   /    */
    0x000000,  /* 33 - Deep red                     /   /    */
    0x000000,  /* 34 - Rose                         /   /    */
    0x000000,  /* 35 - Medium purple                /   /    */
    0x000000,  /* 36 - Purple                       /   /    */
    0x000000,  /* 37 - Orange brown                 /   /    */
    0x000000,  /* 38 - Faded rose                   /   /    */
    0x000000,  /* 39 - Purple-gray                  /   /    */
    0x000000,  /* 40 - Purple-blue                  /   /    */
    0x000000,  /* 41 - Dull chartreuse              /   /    */
    0x000000,  /* 42 - Sage green                   /   /    */
    0x000000,  /* 43 - Gray                         /   /    */
    0x000000,  /* 44 - Light blue-purple            /   /    */
    0x000000,  /* 45 - Chartreuse                   /   /    */
    0x000000,  /* 46 - Pale green                   /   /    */
    0x000000,  /* 47 - Faded blue-green             /   /    */
    0x000000,  /* 48 - Pale cyan                    /   /    */
    0x000000,  /* 49 - Red                          /   /    */
    0x000000,  /* 50 - Hot pink                     /   /    */
    0x000000,  /* 51 - Magenta                      /   /    */
    0x000000,  /* 52 - Light purple                 /   /    */
    0x000000,  /* 53 - Red-orange                   /   /    */
    0x000000,  /* 54 - Pale pink                    /   /    */
    0x000000,  /* 55 - Purple pink                  /   /    */
    0x000000,  /* 56 - Light violet                 /   /    */
    0x000000,  /* 57 - Amber                        /   /    */
    0x000000,  /* 58 - Tan                          /   /    */
    0x000000,  /* 59 - Faded purple                 /   /    */
    0x000000,  /* 60 - Pale purple                  /   /    */
    0x000000,  /* 61 - Yellow                       /   /    */
    0x000000,  /* 62 - Pale yellow                  /   /    */
    0x000000,  /* 63 - Cream                        /   /    */
    0x000000,  /* 64 - White                        /   /    */
};
#endif /* CK_PALETTE_WY370 */

/* The xterm 256-color palette
 *
 * NOTE! These values aren't RGB, they're COLORREF - 0x00bbggrr (ugh)
 */
ULONG RGBTable256[256] = {
    /* First 8 are the standard SGR colors, and the second 8
     * are the intense colors. These are in OS/2 VIO order, *not*
     * SGR/xterm indexed color order  (the number in the comments
     * is the xterm color number */
    0x000000,  /*   0 - Black                      0/  0/  0 */
    0x800000,  /*   4 - Navy (Blue)                0/  0/128 */
    0x008000,  /*   2 - Green                      0/128/  0 */
    0x808000,  /*   3 - Olive (Brown)            128/128/  0 */
    0x000080,  /*   1 - Maroon (Red)             128/  0/  0 */
    0x800080,  /*   5 - Purple (Magenta)         128/  0/128 */
    0x008080,  /*   6 - Teal (Cyan)                0/128/128 */
    0xc0c0c0,  /*   7 - Silver (Light Gray)      192/192/192 */
    0x808080,  /*   8 - Grey (Dark Gray)         128/128/128 */
    0xff0000,  /*  12 - Blue (Light Blue)          0/  0/255 */
    0x00ff00,  /*  10 - Lime (Light Green)         0/255/  0 */
    0xffff00,  /*  11 - Yellow                   255/255/  0 */
    0x0000ff,  /*   9 - Red (Light Red)          255/  0/  0 */
    0xff00ff,  /*  13 - Fuchsia (Light Magenta)  255/  0/255 */
    0x00ffff,  /*  14 - Aqua (Light Cyan)          0/255/255 */
    0xffffff,  /*  15 - White                    255/255/255 */
    /* And the rest is the xterm 256-color palette */
    //BBGGRR
    0x000000,    /*  16 -                            0/  0/  0 */
    0x5F0000,    /*  17 -                            0/  0/ 95 */
    0x870000,    /*  18 -                            0/  0/135 */
    0xAF0000,    /*  19 -                            0/  0/175 */
    0xD70000,    /*  20 -                            0/  0/215 */
    0xFF0000,    /*  21 -                            0/  0/255 */
    0x005F00,    /*  22 -                            0/ 95/  0 */
    0x5F5F00,    /*  23 -                            0/ 95/ 95 */
    0x875F00,    /*  24 -                            0/ 95/135 */
    0xAF5F00,    /*  25 -                            0/ 95/175 */
    0xD75F00,    /*  26 -                            0/ 95/215 */
    0xFF5F00,    /*  27 -                            0/ 95/255 */
    0x008700,    /*  28 -                            0/135/  0 */
    0x5F8700,    /*  29 -                            0/135/ 95 */
    0x878700,    /*  30 -                            0/135/135 */
    0xAF8700,    /*  31 -                            0/135/175 */
    0xD78700,    /*  32 -                            0/135/215 */
    0xFF8700,    /*  33 -                            0/135/255 */
    0x00AF00,    /*  34 -                            0/175/  0 */
    0x5FAF00,    /*  35 -                            0/175/ 95 */
    0x87AF00,    /*  36 -                            0/175/135 */
    0xAFAF00,    /*  37 -                            0/175/175 */
    0xD7AF00,    /*  38 -                            0/175/215 */
    0xFFAF00,    /*  39 -                            0/175/255 */
    0x00D700,    /*  40 -                            0/215/  0 */
    0x5FD700,    /*  41 -                            0/215/ 95 */
    0x87D700,    /*  42 -                            0/215/135 */
    0xAFD700,    /*  43 -                            0/215/175 */
    0xD7D700,    /*  44 -                            0/215/215 */
    0xFFD700,    /*  45 -                            0/215/255 */
    0x00FF00,    /*  46 -                            0/255/  0 */
    0x5FFF00,    /*  47 -                            0/255/ 95 */
    0x87FF00,    /*  48 -                            0/255/135 */
    0xAFFF00,    /*  49 -                            0/255/175 */
    0xD7FF00,    /*  50 -                            0/255/215 */
    0xFFFF00,    /*  51 -                            0/255/255 */
    0x00005F,    /*  52 -                           95/  0/  0 */
    0x5F005F,    /*  53 -                           95/  0/ 95 */
    0x87005F,    /*  54 -                           95/  0/135 */
    0xAF005F,    /*  55 -                           95/  0/175 */
    0xD7005F,    /*  56 -                           95/  0/215 */
    0xFF005F,    /*  57 -                           95/  0/255 */
    0x005F5F,    /*  58 -                           95/ 95/  0 */
    0x5F5F5F,    /*  59 -                           95/ 95/ 95 */
    0x875F5F,    /*  60 -                           95/ 95/135 */
    0xAF5F5F,    /*  61 -                           95/ 95/175 */
    0xD75F5F,    /*  62 -                           95/ 95/215 */
    0xFF5F5F,    /*  63 -                           95/ 95/255 */
    0x00875F,    /*  64 -                           95/135/  0 */
    0x5F875F,    /*  65 -                           95/135/ 95 */
    0x87875F,    /*  66 -                           95/135/135 */
    0xAF875F,    /*  67 -                           95/135/175 */
    0xD7875F,    /*  68 -                           95/135/215 */
    0xFF875F,    /*  69 -                           95/135/255 */
    0x00AF5F,    /*  70 -                           95/175/  0 */
    0x5FAF5F,    /*  71 -                           95/175/ 95 */
    0x87AF5F,    /*  72 -                           95/175/135 */
    0xAFAF5F,    /*  73 -                           95/175/175 */
    0xD7AF5F,    /*  74 -                           95/175/215 */
    0xFFAF5F,    /*  75 -                           95/175/255 */
    0x00D75F,    /*  76 -                           95/215/  0 */
    0x5FD75F,    /*  77 -                           95/215/ 95 */
    0x87D75F,    /*  78 -                           95/215/135 */
    0xAFD75F,    /*  79 -                           95/215/175 */
    0xD7D75F,    /*  80 -                           95/215/215 */
    0xFFD75F,    /*  81 -                           95/215/255 */
    0x00FF5F,    /*  82 -                           95/255/  0 */
    0x5FFF5F,    /*  83 -                           95/255/ 95 */
    0x87FF5F,    /*  84 -                           95/255/135 */
    0xAFFF5F,    /*  85 -                           95/255/175 */
    0xD7FF5F,    /*  86 -                           95/255/215 */
    0xFFFF5F,    /*  87 -                           95/255/255 */
    0x000087,    /*  88 -                          135/  0/  0 */
    0x5F0087,    /*  89 -                          135/  0/ 95 */
    0x870087,    /*  90 -                          135/  0/135 */
    0xAF0087,    /*  91 -                          135/  0/175 */
    0xD70087,    /*  92 -                          135/  0/215 */
    0xFF0087,    /*  93 -                          135/  0/255 */
    0x005F87,    /*  94 -                          135/ 95/  0 */
    0x5F5F87,    /*  95 -                          135/ 95/ 95 */
    0x875F87,    /*  96 -                          135/ 95/135 */
    0xAF5F87,    /*  97 -                          135/ 95/175 */
    0xD75F87,    /*  98 -                          135/ 95/215 */
    0xFF5F87,    /*  99 -                          135/ 95/255 */
    0x008787,    /* 100 -                          135/135/  0 */
    0x5F8787,    /* 101 -                          135/135/ 95 */
    0x878787,    /* 102 -                          135/135/135 */
    0xAF8787,    /* 103 -                          135/135/175 */
    0xD78787,    /* 104 -                          135/135/215 */
    0xFF8787,    /* 105 -                          135/135/255 */
    0x00AF87,    /* 106 -                          135/175/  0 */
    0x5FAF87,    /* 107 -                          135/175/ 95 */
    0x87AF87,    /* 108 -                          135/175/135 */
    0xAFAF87,    /* 109 -                          135/175/175 */
    0xD7AF87,    /* 110 -                          135/175/215 */
    0xFFAF87,    /* 111 -                          135/175/255 */
    0x00D787,    /* 112 -                          135/215/  0 */
    0x5FD787,    /* 113 -                          135/215/ 95 */
    0x87D787,    /* 114 -                          135/215/135 */
    0xAFD787,    /* 115 -                          135/215/175 */
    0xD7D787,    /* 116 -                          135/215/215 */
    0xFFD787,    /* 117 -                          135/215/255 */
    0x00FF87,    /* 118 -                          135/255/  0 */
    0x5FFF87,    /* 119 -                          135/255/ 95 */
    0x87FF87,    /* 120 -                          135/255/135 */
    0xAFFF87,    /* 121 -                          315/255/175 */
    0xD7FF87,    /* 122 -                          135/255/215 */
    0xFFFF87,    /* 123 -                          135/255/255 */
    0x0000AF,    /* 124 -                          175/  0/  0 */
    0x5F00AF,    /* 125 -                          175/  0/ 95 */
    0x8700AF,    /* 126 -                          175/  0/135 */
    0xAF00AF,    /* 127 -                          175/  0/175 */
    0xD700AF,    /* 128 -                          175/  0/215 */
    0xFF00AF,    /* 129 -                          175/  0/255 */
    0x005FAF,    /* 130 -                          175/ 95/  0 */
    0x5F5FAF,    /* 131 -                          175/ 95/ 95 */
    0x875FAF,    /* 132 -                          175/ 95/135 */
    0xAF5FAF,    /* 133 -                          175/ 95/175 */
    0xD75FAF,    /* 134 -                          175/ 95/215 */
    0xFF5FAF,    /* 135 -                          175/ 95/255 */
    0x0087AF,    /* 136 -                          175/135/  0 */
    0x5F87AF,    /* 137 -                          175/135/ 95 */
    0x8787AF,    /* 138 -                          175/135/135 */
    0xAF87AF,    /* 139 -                          175/135/175 */
    0xD787AF,    /* 140 -                          175/135/215 */
    0xFF87AF,    /* 141 -                          175/135/255 */
    0x00AFAF,    /* 142 -                          175/175/  0 */
    0x5FAFAF,    /* 143 -                          175/175/ 95 */
    0x87AFAF,    /* 144 -                          175/175/135 */
    0xAFAFAF,    /* 145 -                          175/175/175 */
    0xD7AFAF,    /* 146 -                          175/175/215 */
    0xFFAFAF,    /* 147 -                          175/175/255 */
    0x00D7AF,    /* 148 -                          175/215/  0 */
    0x5FD7AF,    /* 149 -                          175/215/ 95 */
    0x87D7AF,    /* 150 -                          175/215/135 */
    0xAFD7AF,    /* 151 -                          175/215/175 */
    0xD7D7AF,    /* 152 -                          175/215/215 */
    0xFFD7AF,    /* 153 -                          175/215/255 */
    0x00FFAF,    /* 154 -                          175/255/  0 */
    0x5FFFAF,    /* 155 -                          175/255/ 95 */
    0x87FFAF,    /* 156 -                          175/255/135 */
    0xAFFFAF,    /* 157 -                          175/255/175 */
    0xD7FFAF,    /* 158 -                          175/255/215 */
    0xFFFFAF,    /* 159 -                          175/255/255 */
    0x0000A7,    /* 160 -                          215/  0/  0 */
    0x5F00D7,    /* 161 -                          215/  0/ 95 */
    0x8700D7,    /* 162 -                          215/  0/135 */
    0xAF00D7,    /* 163 -                          215/  0/175 */
    0xD700D7,    /* 164 -                          215/  0/215 */
    0xFF00D7,    /* 165 -                          215/  0/255 */
    0x005FD7,    /* 166 -                          215/ 95/  0 */
    0x5F5FD7,    /* 167 -                          215/ 95/ 95 */
    0x875FD7,    /* 168 -                          215/ 95/135 */
    0xAF5FD7,    /* 169 -                          215/ 95/175 */
    0xD75FD7,    /* 170 -                          215/ 95/215 */
    0xFF5FD7,    /* 171 -                          215/ 95/255 */
    0x0087D7,    /* 172 -                          215/135/  0 */
    0x5F87D7,    /* 173 -                          215/135/ 95 */
    0x8787D7,    /* 174 -                          215/135/135 */
    0xAF87D7,    /* 175 -                          215/135/175 */
    0xD787D7,    /* 176 -                          215/135/215 */
    0xFF87D7,    /* 177 -                          215/135/255 */
    0x00AFD7,    /* 178 -                          215/175/  0 */
    0x5FAFD7,    /* 179 -                          215/175/ 95 */
    0x87AFD7,    /* 180 -                          215/175/135 */
    0xAFAFD7,    /* 181 -                          215/175/175 */
    0xD7AFD7,    /* 182 -                          215/175/215 */
    0xFFAFD7,    /* 183 -                          215/175/255 */
    0x00D7D7,    /* 184 -                          215/215/  0 */
    0x5FD7D7,    /* 185 -                          215/215/ 95 */
    0x87D7D7,    /* 186 -                          215/215/135 */
    0xAFD7D7,    /* 187 -                          215/215/175 */
    0xD7D7D7,    /* 188 -                          215/215/215 */
    0xFFD7D7,    /* 189 -                          215/215/255 */
    0x00FFD7,    /* 190 -                          215/255/  0 */
    0x5FFFD7,    /* 191 -                          215/255/ 95 */
    0x87FFD7,    /* 192 -                          215/255/135 */
    0xAFFFD7,    /* 193 -                          215/255/175 */
    0xD7FFD7,    /* 194 -                          215/255/215 */
    0xFFFFD7,    /* 195 -                          215/255/255 */
    0x0000FF,    /* 196 -                          255/  0/  0 */
    0x5F00FF,    /* 197 -                          255/  0/ 95 */
    0x8700FF,    /* 198 -                          255/  0/135 */
    0xAF00FF,    /* 199 -                          255/  0/175 */
    0xD700FF,    /* 200 -                          255/  0/215 */
    0xFF00FF,    /* 201 -                          255/  0/255 */
    0x005FFF,    /* 202 -                          255/ 95/  0 */
    0x5F5FFF,    /* 203 -                          255/ 95/ 95 */
    0x875FFF,    /* 204 -                          255/ 95/135 */
    0xAF5FFF,    /* 205 -                          255/ 95/175 */
    0xD75FFF,    /* 206 -                          255/ 95/215 */
    0xFF5FFF,    /* 207 -                          255/ 95/255 */
    0x0087FF,    /* 208 -                          255/135/  0 */
    0x5F87FF,    /* 209 -                          255/135/ 95 */
    0x8787FF,    /* 210 -                          255/135/135 */
    0xAF87FF,    /* 211 -                          255/135/175 */
    0xD787FF,    /* 212 -                          255/135/215 */
    0xFF87FF,    /* 213 -                          255/135/255 */
    0x00AFFF,    /* 214 -                          255/175/  0 */
    0x5FAFFF,    /* 215 -                          255/175/ 95 */
    0x87AFFF,    /* 216 -                          255/175/135 */
    0xAFAFFF,    /* 217 -                          255/175/175 */
    0xD7AFFF,    /* 218 -                          255/175/215 */
    0xFFAFFF,    /* 219 -                          255/175/255 */
    0x00D7FF,    /* 220 -                          255/215/  0 */
    0x5FD7FF,    /* 221 -                          255/215/ 95 */
    0x87D7FF,    /* 222 -                          255/215/135 */
    0xAFD7FF,    /* 223 -                          255/215/175 */
    0xD7D7FF,    /* 224 -                          255/215/215 */
    0xFFD7FF,    /* 225 -                          255/215/255 */
    0x00FFFF,    /* 226 -                          255/255/  0 */
    0x5FFFFF,    /* 227 -                          255/255/ 95 */
    0x87FFFF,    /* 228 -                          255/255/135 */
    0xAFFFFF,    /* 229 -                          255/255/175 */
    0xD7FFFF,    /* 230 -                          255/255/215 */
    0xFFFFFF,    /* 231 -                          255/255/255 */
    0x080808,    /* 232 -                            8/  8/  8 */
    0x121212,    /* 233 -                           18/ 18/ 18 */
    0x1C1C1C,    /* 234 -                           28/ 28/ 28 */
    0x262626,    /* 235 -                           38/ 38/ 38 */
    0x303030,    /* 236 -                           48/ 48/ 48 */
    0x3A3A3A,    /* 237 -                           58/ 58/ 58 */
    0x444444,    /* 238 -                           68/ 68/ 68 */
    0x4E4E4E,    /* 239 -                           78/ 78/ 78 */
    0x585858,    /* 240 -                           88/ 88/ 88 */
    0x606060,    /* 241 -                           98/ 98/ 98 */
    0x666666,    /* 242 -                          108/108/108 */
    0x767676,    /* 243 -                          118/118/118 */
    0x808080,    /* 244 -                          128/128/128 */
    0x8A8A8A,    /* 245 -                          138/138/138 */
    0x949494,    /* 246 -                          148/148/148 */
    0x9E9E9E,    /* 247 -                          158/158/158 */
    0xA8A8A8,    /* 248 -                          168/168/168 */
    0xB2B2B2,    /* 249 -                          178/178/178 */
    0xBCBCBC,    /* 250 -                          188/188/188 */
    0xC6C6C6,    /* 251 -                          198/198/198 */
    0xD0D0D0,    /* 252 -                          208/208/208 */
    0xDADADA,    /* 253 -                          218/218/218 */
    0xE4E4E4,    /* 254 -                          228/228/228 */
    0xEEEEEE     /* 255 -                          238/238/238 */
};


/* The xterm 88-color palette
 *
 * NOTE! These values aren't RGB, they're COLORREF - 0x00bbggrr (ugh)
 */
ULONG RGBTable88[88] = {
    /* First 8 are the standard SGR colors, and the second 8
     * are the intense colors. These are in OS/2 VIO order, *not*
     * SGR/xterm indexed color order  (the number in the comments
     * is the xterm color number */
    0x000000,  /*   0 - Black                      0/  0/  0 */
    0x800000,  /*   4 - Navy (Blue)                0/  0/128 */
    0x008000,  /*   2 - Green                      0/128/  0 */
    0x808000,  /*   3 - Olive (Brown)            128/128/  0 */
    0x000080,  /*   1 - Maroon (Red)             128/  0/  0 */
    0x800080,  /*   5 - Purple (Magenta)         128/  0/128 */
    0x008080,  /*   6 - Teal (Cyan)                0/128/128 */
    0xc0c0c0,  /*   7 - Silver (Light Gray)      192/192/192 */
    0x808080,  /*   8 - Grey (Dark Gray)         128/128/128 */
    0xff0000,  /*  12 - Blue (Light Blue)          0/  0/255 */
    0x00ff00,  /*  10 - Lime (Light Green)         0/255/  0 */
    0xffff00,  /*  11 - Yellow                   255/255/  0 */
    0x0000ff,  /*   9 - Red (Light Red)          255/  0/  0 */
    0xff00ff,  /*  13 - Fuchsia (Light Magenta)  255/  0/255 */
    0x00ffff,  /*  14 - Aqua (Light Cyan)          0/255/255 */
    0xffffff,  /*  15 - White                    255/255/255 */
    /* And the rest is the xterm 256-color palette */
    //BBGGRR
    0x000000,  /* 16 -                            00/ 00/ 00 */
    0x00008B,  /* 17 -                            00/ 00/ 8b */
    0x0000CD,  /* 18 -                            00/ 00/ cd */
    0x0000FF,  /* 19 -                            00/ 00/ ff */
    0x008B00,  /* 20 -                            00/ 8b/ 00 */
    0x008B8B,  /* 21 -                            00/ 8b/ 8b */
    0x008BCD,  /* 22 -                            00/ 8b/ cd */
    0x008BFF,  /* 23 -                            00/ 8b/ ff */
    0x00CD00,  /* 24 -                            00/ cd/ 00 */
    0x00CD8B,  /* 25 -                            00/ cd/ 8b */
    0x00CDCD,  /* 26 -                            00/ cd/ cd */
    0x00CDFF,  /* 27 -                            00/ cd/ ff */
    0x00FF00,  /* 28 -                            00/ ff/ 00 */
    0x00FF8B,  /* 29 -                            00/ ff/ 8b */
    0x00FFCD,  /* 30 -                            00/ ff/ cd */
    0x00FFFF,  /* 31 -                            00/ ff/ ff */
    0x8B0000,  /* 32 -                            8b/ 00/ 00 */
    0x8B008B,  /* 33 -                            8b/ 00/ 8b */
    0x8B00CD,  /* 34 -                            8b/ 00/ cd */
    0x8B00FF,  /* 35 -                            8b/ 00/ ff */
    0x8B8B00,  /* 36 -                            8b/ 8b/ 00 */
    0x8B8B8B,  /* 37 -                            8b/ 8b/ 8b */
    0x8B8BCD,  /* 38 -                            8b/ 8b/ cd */
    0x8B8BFF,  /* 39 -                            8b/ 8b/ ff */
    0x8BCD00,  /* 40 -                            8b/ cd/ 00 */
    0x8BCD8B,  /* 41 -                            8b/ cd/ 8b */
    0x8BCDCD,  /* 42 -                            8b/ cd/ cd */
    0x8BCDFF,  /* 43 -                            8b/ cd/ ff */
    0x8BFF00,  /* 44 -                            8b/ ff/ 00 */
    0x8BFF8B,  /* 45 -                            8b/ ff/ 8b */
    0x8BFFCD,  /* 46 -                            8b/ ff/ cd */
    0x8BFFFF,  /* 47 -                            8b/ ff/ ff */
    0xCD0000,  /* 48 -                            cd/ 00/ 00 */
    0xCD008B,  /* 49 -                            cd/ 00/ 8b */
    0xCD00CD,  /* 50 -                            cd/ 00/ cd */
    0xCD00FF,  /* 51 -                            cd/ 00/ ff */
    0xCD8B00,  /* 52 -                            cd/ 8b/ 00 */
    0xCD8B8B,  /* 53 -                            cd/ 8b/ 8b */
    0xCD8BCD,  /* 54 -                            cd/ 8b/ cd */
    0xCD8BFF,  /* 55 -                            cd/ 8b/ ff */
    0xCDCD00,  /* 56 -                            cd/ cd/ 00 */
    0xCDCD8B,  /* 57 -                            cd/ cd/ 8b */
    0xCDCDCD,  /* 58 -                            cd/ cd/ cd */
    0xCDCDFF,  /* 59 -                            cd/ cd/ ff */
    0xCDFF00,  /* 60 -                            cd/ ff/ 00 */
    0xCDFF8B,  /* 61 -                            cd/ ff/ 8b */
    0xCDFFCD,  /* 62 -                            cd/ ff/ cd */
    0xCDFFFF,  /* 63 -                            cd/ ff/ ff */
    0xFF0000,  /* 64 -                            ff/ 00/ 00 */
    0xFF008B,  /* 65 -                            ff/ 00/ 8b */
    0xFF00CD,  /* 66 -                            ff/ 00/ cd */
    0xFF00FF,  /* 67 -                            ff/ 00/ ff */
    0xFF8B00,  /* 68 -                            ff/ 8b/ 00 */
    0xFF8B8B,  /* 69 -                            ff/ 8b/ 8b */
    0xFF8BCD,  /* 70 -                            ff/ 8b/ cd */
    0xFF8BFF,  /* 71 -                            ff/ 8b/ ff */
    0xFFCD00,  /* 72 -                            ff/ cd/ 00 */
    0xFFCD8B,  /* 73 -                            ff/ cd/ 8b */
    0xFFCDCD,  /* 74 -                            ff/ cd/ cd */
    0xFFCDFF,  /* 75 -                            ff/ cd/ ff */
    0xFFFF00,  /* 76 -                            ff/ ff/ 00 */
    0xFFFF8B,  /* 77 -                            ff/ ff/ 8b */
    0xFFFFCD,  /* 78 -                            ff/ ff/ cd */
    0xFFFFFF,  /* 79 -                            ff/ ff/ ff */
    0x2E2E2E,  /* 80 -                            2e/ 2e/ 2e */
    0x5C5C5C,  /* 81 -                            5c/ 5c/ 5c */
    0x737373,  /* 82 -                            73/ 73/ 73 */
    0x8B8B8B,  /* 83 -                            8b/ 8b/ 8b */
    0xA2A2A2,  /* 84 -                            a2/ a2/ a2 */
    0xB9B9B9,  /* 85 -                            b9/ b9/ b9 */
    0xD0D0D0,  /* 86 -                            d0/ d0/ d0 */
    0xE7E7E7,  /* 87 -                            e7/ e7/ e7 */
};

/* The standard 16 color palette.
 *
 * NOTE! These values aren't RGB, they're COLORREF - 0x00bbggrr (ugh)
 */
ULONG RGBTable[16] = {
    /* First 8 are the standard SGR colors, and the second 8
     * are the intense colors. These are in OS/2 VIO order, *not*
     * SGR/xterm indexed color order  (the number in the comments
     * is the xterm color number */
    0x000000,  /*   0 - Black                      0/  0/  0 */
    0x800000,  /*   4 - Navy (Blue)                0/  0/128 */
    0x008000,  /*   2 - Green                      0/128/  0 */
    0x808000,  /*   3 - Olive (Brown)            128/128/  0 */
    0x000080,  /*   1 - Maroon (Red)             128/  0/  0 */
    0x800080,  /*   5 - Purple (Magenta)         128/  0/128 */
    0x008080,  /*   6 - Teal (Cyan)                0/128/128 */
    0xc0c0c0,  /*   7 - Silver (Light Gray)      192/192/192 */
    0x808080,  /*   8 - Grey (Dark Gray)         128/128/128 */
    0xff0000,  /*  12 - Blue (Light Blue)          0/  0/255 */
    0x00ff00,  /*  10 - Lime (Light Green)         0/255/  0 */
    0xffff00,  /*  11 - Yellow                   255/255/  0 */
    0x0000ff,  /*   9 - Red (Light Red)          255/  0/  0 */
    0xff00ff,  /*  13 - Fuchsia (Light Magenta)  255/  0/255 */
    0x00ffff,  /*  14 - Aqua (Light Cyan)          0/255/255 */
    0xffffff,  /*  15 - White                    255/255/255 */
};

/* The VT525 16 color palette - same as the standard one, just
 * with different defaults.
 */
ULONG VT525RGBTable[16] = {
    /* First 8 are the standard SGR colors on the VT525, and the
     * second 8 are lighter versions. These are in OS/2 VIO order
     * (swapped red and blue), *not* SGR color order (the number
     * in the comments is the SGR color number */
    0x000000,  /*   0 - Black                      0/  0/  0 */
    0xcc3333,  /*   4 - Blue                      51/ 51/204 */
    0x33cc33,  /*   2 - Green                     51/204/ 51 */
    0xcccc33,  /*   3 - Yellow                   204/204/ 51 */
    0x2424cc,  /*   1 - Red                      204/ 36/ 36 */
    0xcc33cc,  /*   5 - Magenta                  204/ 51/204 */
    0x33cccc,  /*   6 - Cyan                      51/204/204 */
    0x787878,  /*   7 - Grey                     120/120/120 */
    0x000000,  /*   8 - Black                      0/  0/  0 */
    0xFF0000,  /*  12 - Light Blue                 0/  0/255 */
    0x00FF00,  /*  10 - Light Green                0/255/  0 */
    0xFFFF00,  /*  11 - Light Yellow             255/255/  0 */
    0x0000FF,  /*   9 - Light Red                255/  0/  0 */
    0xFF00FF,  /*  13 - Light Magenta            255/  0/255 */
    0x00ffff,  /*  14 - Light Cyan                 0/255/255 */
    0xFFFFFF,  /*  15 - White                    255/255/255 */
};

/* VT525 Alternate Colors - selected via DECSTGLT only, so colors
 * are in DECATC order. */
ULONG VT525ATCRGBTable[16] = {
    /* In DECATC order, as colors from this palette aren't selected
     * via SGR color attributes. */
    0x000000,  /*   0 - Black                      0/  0/  0 */
    0xcc3333,  /*   1 - Blue                      51/ 51/204 */
    0x2424cc,  /*   2 - Red                      204/ 36/ 36 */
    0x33cc33,  /*   3 - Green                     51/204/ 51 */
    0xcc33cc,  /*   4 - Magenta                  204/ 51/204 */
    0xcccc33,  /*   5 - Cyan                      51/204/204 */
    0x33cccc,  /*   6 - Yellow                   204/204/ 51 */
    0x787878,  /*   7 - Gray 50%                 120/120/120 */
    0x454545,  /*   8 - Gray 25%                  69/ 69/ 69 */
    0x995757,  /*   9 - Light Blue                87/ 87/153 */
    0x454599,  /*  10 - Light Red                153/ 69/ 69 */
    0x579957,  /*  11 - Light Green               87/153/ 87 */
    0x995799,  /*  12 - Light Magenta            153/ 87/153 */
    0x999957,  /*  13 - Light Cyan                87/153/153 */
    0x579999,  /*  14 - Light Yellow             153/153/ 87 */
    0xcccccc,  /*  15 - Gray 75%                 204/204/204 */
};

/* The VT525 mono palette, in OS/2 VIO order */
ULONG VT525MonoRGBTable[16] = {  /* VT
    /* First 8 are the standard SGR colors on the VT525, and the
     * second 8 are lighter versions. These are in OS/2 VIO order
     * (swapped red and blue), *not* SGR color order (the number
     * in the comments is the SGR color number */
    0x000000,  /*   0                              0/  0/  0 */
    0x242424,  /*   4                             36/ 36/ 36 */
    0x8a8a8a,  /*   2                            138/138/138 */
    0xcccccc,  /*   3                            204/204/204 */
    0x454545,  /*   1                             69/ 69/ 69 */
    0x666666,  /*   5                            102/102/102 */
    0xababab,  /*   6                            171/171/171 */
    0x787878,  /*   7                            120/120/120 */
    0x121212,  /*   8                             18/ 18/ 18 */
    0x333333,  /*  12                             51/ 51/ 51 */
    0x999999,  /*  10                            153/153/153 */
    0xdedede,  /*  11                            222/222/222 */
    0x575757,  /*   9                             87/ 87/ 87 */
    0x787878,  /*  13                            120/120/120 */
    0xbdbdbd,  /*  14                            189/189/189 */
    0xcccccc,  /*  15                            204/204/204 */
};

/* X11 color names - required by OSC 4/5 and various other operating system
 * commands that set colors */
typedef struct _x11color {
    char* name;
    unsigned char red;
    unsigned char green;
    unsigned char blue;
} x11color;

x11color x11colors[783] = {
    {"snow",                  255, 250, 250},
    {"ghost white",           248, 248, 255},
    {"GhostWhite",            248, 248, 255},
    {"white smoke",           245, 245, 245},
    {"WhiteSmoke",            245, 245, 245},
    {"gainsboro",             220, 220, 220},
    {"floral white",          255, 250, 240},
    {"FloralWhite",           255, 250, 240},
    {"old lace",              253, 245, 230},
    {"OldLace",               253, 245, 230},
    {"linen",                 250, 240, 230},
    {"antique white",         250, 235, 215},
    {"AntiqueWhite",          250, 235, 215},
    {"papaya whip",           255, 239, 213},
    {"PapayaWhip",            255, 239, 213},
    {"blanched almond",       255, 235, 205},
    {"BlanchedAlmond",        255, 235, 205},
    {"bisque",                255, 228, 196},
    {"peach puff",            255, 218, 185},
    {"PeachPuff",             255, 218, 185},
    {"navajo white",          255, 222, 173},
    {"NavajoWhite",           255, 222, 173},
    {"moccasin",              255, 228, 181},
    {"cornsilk",              255, 248, 220},
    {"ivory",                 255, 255, 240},
    {"lemon chiffon",         255, 250, 205},
    {"LemonChiffon",          255, 250, 205},
    {"seashell",              255, 245, 238},
    {"honeydew",              240, 255, 240},
    {"mint cream",            245, 255, 250},
    {"MintCream",             245, 255, 250},
    {"azure",                 240, 255, 255},
    {"alice blue",            240, 248, 255},
    {"AliceBlue",             240, 248, 255},
    {"lavender",              230, 230, 250},
    {"lavender blush",        255, 240, 245},
    {"LavenderBlush",         255, 240, 245},
    {"misty rose",            255, 228, 225},
    {"MistyRose",             255, 228, 225},
    {"white",                 255, 255, 255},
    {"black",                 0  , 0  , 0  },
    {"dark slate gray",       47 , 79 , 79 },
    {"DarkSlateGray",         47 , 79 , 79 },
    {"dark slate grey",       47 , 79 , 79 },
    {"DarkSlateGrey",         47 , 79 , 79 },
    {"dim gray",              105, 105, 105},
    {"DimGray",               105, 105, 105},
    {"dim grey",              105, 105, 105},
    {"DimGrey",               105, 105, 105},
    {"slate gray",            112, 128, 144},
    {"SlateGray",             112, 128, 144},
    {"slate grey",            112, 128, 144},
    {"SlateGrey",             112, 128, 144},
    {"light slate gray",      119, 136, 153},
    {"LightSlateGray",        119, 136, 153},
    {"light slate grey",      119, 136, 153},
    {"LightSlateGrey",        119, 136, 153},
    {"gray",                  190, 190, 190},
    {"grey",                  190, 190, 190},
    {"x11 gray",              190, 190, 190},
    {"X11Gray",               190, 190, 190},
    {"x11 grey",              190, 190, 190},
    {"X11Grey",               190, 190, 190},
    {"web gray",              128, 128, 128},
    {"WebGray",               128, 128, 128},
    {"web grey",              128, 128, 128},
    {"WebGrey",               128, 128, 128},
    {"light grey",            211, 211, 211},
    {"LightGrey",             211, 211, 211},
    {"light gray",            211, 211, 211},
    {"LightGray",             211, 211, 211},
    {"midnight blue",         25 , 25 , 112},
    {"MidnightBlue",          25 , 25 , 112},
    {"navy",                  0  , 0  , 128},
    {"navy blue",             0  , 0  , 128},
    {"NavyBlue",              0  , 0  , 128},
    {"cornflower blue",       100, 149, 237},
    {"CornflowerBlue",        100, 149, 237},
    {"dark slate blue",       72 , 61 , 139},
    {"DarkSlateBlue",         72 , 61 , 139},
    {"slate blue",            106, 90 , 205},
    {"SlateBlue",             106, 90 , 205},
    {"medium slate blue",     123, 104, 238},
    {"MediumSlateBlue",       123, 104, 238},
    {"light slate blue",      132, 112, 255},
    {"LightSlateBlue",        132, 112, 255},
    {"medium blue",           0  , 0  , 205},
    {"MediumBlue",            0  , 0  , 205},
    {"royal blue",            65 , 105, 225},
    {"RoyalBlue",             65 , 105, 225},
    {"blue",                  0  , 0  , 255},
    {"dodger blue",           30 , 144, 255},
    {"DodgerBlue",            30 , 144, 255},
    {"deep sky blue",         0  , 191, 255},
    {"DeepSkyBlue",           0  , 191, 255},
    {"sky blue",              135, 206, 235},
    {"SkyBlue",               135, 206, 235},
    {"light sky blue",        135, 206, 250},
    {"LightSkyBlue",          135, 206, 250},
    {"steel blue",            70 , 130, 180},
    {"SteelBlue",             70 , 130, 180},
    {"light steel blue",      176, 196, 222},
    {"LightSteelBlue",        176, 196, 222},
    {"light blue",            173, 216, 230},
    {"LightBlue",             173, 216, 230},
    {"powder blue",           176, 224, 230},
    {"PowderBlue",            176, 224, 230},
    {"pale turquoise",        175, 238, 238},
    {"PaleTurquoise",         175, 238, 238},
    {"dark turquoise",        0  , 206, 209},
    {"DarkTurquoise",         0  , 206, 209},
    {"medium turquoise",      72 , 209, 204},
    {"MediumTurquoise",       72 , 209, 204},
    {"turquoise",             64 , 224, 208},
    {"cyan",                  0  , 255, 255},
    {"aqua",                  0  , 255, 255},
    {"light cyan",            224, 255, 255},
    {"LightCyan",             224, 255, 255},
    {"cadet blue",            95 , 158, 160},
    {"CadetBlue",             95 , 158, 160},
    {"medium aquamarine",     102, 205, 170},
    {"MediumAquamarine",      102, 205, 170},
    {"aquamarine",            127, 255, 212},
    {"dark green",            0  , 100, 0  },
    {"DarkGreen",             0  , 100, 0  },
    {"dark olive green",      85 , 107, 47 },
    {"DarkOliveGreen",        85 , 107, 47 },
    {"dark sea green",        143, 188, 143},
    {"DarkSeaGreen",          143, 188, 143},
    {"sea green",             46 , 139, 87 },
    {"SeaGreen",              46 , 139, 87 },
    {"medium sea green",      60 , 179, 113},
    {"MediumSeaGreen",        60 , 179, 113},
    {"light sea green",       32 , 178, 170},
    {"LightSeaGreen",         32 , 178, 170},
    {"pale green",            152, 251, 152},
    {"PaleGreen",             152, 251, 152},
    {"spring green",          0  , 255, 127},
    {"SpringGreen",           0  , 255, 127},
    {"lawn green",            124, 252, 0  },
    {"LawnGreen",             124, 252, 0  },
    {"green",                 0  , 255, 0  },
    {"lime",                  0  , 255, 0  },
    {"x11 green",             0  , 255, 0  },
    {"X11Green",              0  , 255, 0  },
    {"web green",             0  , 128, 0  },
    {"WebGreen",              0  , 128, 0  },
    {"chartreuse",            127, 255, 0  },
    {"medium spring green",   0  , 250, 154},
    {"MediumSpringGreen",     0  , 250, 154},
    {"green yellow",          173, 255, 47 },
    {"GreenYellow",           173, 255, 47 },
    {"lime green",            50 , 205, 50 },
    {"LimeGreen",             50 , 205, 50 },
    {"yellow green",          154, 205, 50 },
    {"YellowGreen",           154, 205, 50 },
    {"forest green",          34 , 139, 34 },
    {"ForestGreen",           34 , 139, 34 },
    {"olive drab",            107, 142, 35 },
    {"OliveDrab",             107, 142, 35 },
    {"dark khaki",            189, 183, 107},
    {"DarkKhaki",             189, 183, 107},
    {"khaki",                 240, 230, 140},
    {"pale goldenrod",        238, 232, 170},
    {"PaleGoldenrod",         238, 232, 170},
    {"light goldenrod yellow",250, 250, 210},
    {"LightGoldenrodYellow",  250, 250, 210},
    {"light yellow",          255, 255, 224},
    {"LightYellow",           255, 255, 224},
    {"yellow",                255, 255, 0  },
    {"gold",                  255, 215, 0  },
    {"light goldenrod",       238, 221, 130},
    {"LightGoldenrod",        238, 221, 130},
    {"goldenrod",             218, 165, 32 },
    {"dark goldenrod",        184, 134, 11 },
    {"DarkGoldenrod",         184, 134, 11 },
    {"rosy brown",            188, 143, 143},
    {"RosyBrown",             188, 143, 143},
    {"indian red",            205, 92 , 92 },
    {"IndianRed",             205, 92 , 92 },
    {"saddle brown",          139, 69 , 19 },
    {"SaddleBrown",           139, 69 , 19 },
    {"sienna",                160, 82 , 45 },
    {"peru",                  205, 133, 63 },
    {"burlywood",             222, 184, 135},
    {"beige",                 245, 245, 220},
    {"wheat",                 245, 222, 179},
    {"sandy brown",           244, 164, 96 },
    {"SandyBrown",            244, 164, 96 },
    {"tan",                   210, 180, 140},
    {"chocolate",             210, 105, 30 },
    {"firebrick",             178, 34 , 34 },
    {"brown",                 165, 42 , 42 },
    {"dark salmon",           233, 150, 122},
    {"DarkSalmon",            233, 150, 122},
    {"salmon",                250, 128, 114},
    {"light salmon",          255, 160, 122},
    {"LightSalmon",           255, 160, 122},
    {"orange",                255, 165, 0  },
    {"dark orange",           255, 140, 0  },
    {"DarkOrange",            255, 140, 0  },
    {"coral",                 255, 127, 80 },
    {"light coral",           240, 128, 128},
    {"LightCoral",            240, 128, 128},
    {"tomato",                255, 99 , 71 },
    {"orange red",            255, 69 , 0  },
    {"OrangeRed",             255, 69 , 0  },
    {"red",                   255, 0  , 0  },
    {"hot pink",              255, 105, 180},
    {"HotPink",               255, 105, 180},
    {"deep pink",             255, 20 , 147},
    {"DeepPink",              255, 20 , 147},
    {"pink",                  255, 192, 203},
    {"light pink",            255, 182, 193},
    {"LightPink",             255, 182, 193},
    {"pale violet red",       219, 112, 147},
    {"PaleVioletRed",         219, 112, 147},
    {"maroon",                176, 48 , 96 },
    {"x11 maroon",            176, 48 , 96 },
    {"X11Maroon",             176, 48 , 96 },
    {"web maroon",            128, 0  , 0  },
    {"WebMaroon",             128, 0  , 0  },
    {"medium violet red",     199, 21 , 133},
    {"MediumVioletRed",       199, 21 , 133},
    {"violet red",            208, 32 , 144},
    {"VioletRed",             208, 32 , 144},
    {"magenta",               255, 0  , 255},
    {"fuchsia",               255, 0  , 255},
    {"violet",                238, 130, 238},
    {"plum",                  221, 160, 221},
    {"orchid",                218, 112, 214},
    {"medium orchid",         186, 85 , 211},
    {"MediumOrchid",          186, 85 , 211},
    {"dark orchid",           153, 50 , 204},
    {"DarkOrchid",            153, 50 , 204},
    {"dark violet",           148, 0  , 211},
    {"DarkViolet",            148, 0  , 211},
    {"blue violet",           138, 43 , 226},
    {"BlueViolet",            138, 43 , 226},
    {"purple",                160, 32 , 240},
    {"x11 purple",            160, 32 , 240},
    {"X11Purple",             160, 32 , 240},
    {"web purple",            128, 0  , 128},
    {"WebPurple",             128, 0  , 128},
    {"medium purple",         147, 112, 219},
    {"MediumPurple",          147, 112, 219},
    {"thistle",               216, 191, 216},
    {"snow1",                 255, 250, 250},
    {"snow2",                 238, 233, 233},
    {"snow3",                 205, 201, 201},
    {"snow4",                 139, 137, 137},
    {"seashell1",             255, 245, 238},
    {"seashell2",             238, 229, 222},
    {"seashell3",             205, 197, 191},
    {"seashell4",             139, 134, 130},
    {"AntiqueWhite1",         255, 239, 219},
    {"AntiqueWhite2",         238, 223, 204},
    {"AntiqueWhite3",         205, 192, 176},
    {"AntiqueWhite4",         139, 131, 120},
    {"bisque1",               255, 228, 196},
    {"bisque2",               238, 213, 183},
    {"bisque3",               205, 183, 158},
    {"bisque4",               139, 125, 107},
    {"PeachPuff1",            255, 218, 185},
    {"PeachPuff2",            238, 203, 173},
    {"PeachPuff3",            205, 175, 149},
    {"PeachPuff4",            139, 119, 101},
    {"NavajoWhite1",          255, 222, 173},
    {"NavajoWhite2",          238, 207, 161},
    {"NavajoWhite3",          205, 179, 139},
    {"NavajoWhite4",          139, 121, 94 },
    {"LemonChiffon1",         255, 250, 205},
    {"LemonChiffon2",         238, 233, 191},
    {"LemonChiffon3",         205, 201, 165},
    {"LemonChiffon4",         139, 137, 112},
    {"cornsilk1",             255, 248, 220},
    {"cornsilk2",             238, 232, 205},
    {"cornsilk3",             205, 200, 177},
    {"cornsilk4",             139, 136, 120},
    {"ivory1",                255, 255, 240},
    {"ivory2",                238, 238, 224},
    {"ivory3",                205, 205, 193},
    {"ivory4",                139, 139, 131},
    {"honeydew1",             240, 255, 240},
    {"honeydew2",             224, 238, 224},
    {"honeydew3",             193, 205, 193},
    {"honeydew4",             131, 139, 131},
    {"LavenderBlush1",        255, 240, 245},
    {"LavenderBlush2",        238, 224, 229},
    {"LavenderBlush3",        205, 193, 197},
    {"LavenderBlush4",        139, 131, 134},
    {"MistyRose1",            255, 228, 225},
    {"MistyRose2",            238, 213, 210},
    {"MistyRose3",            205, 183, 181},
    {"MistyRose4",            139, 125, 123},
    {"azure1",                240, 255, 255},
    {"azure2",                224, 238, 238},
    {"azure3",                193, 205, 205},
    {"azure4",                131, 139, 139},
    {"SlateBlue1",            131, 111, 255},
    {"SlateBlue2",            122, 103, 238},
    {"SlateBlue3",            105, 89 , 205},
    {"SlateBlue4",            71 , 60 , 139},
    {"RoyalBlue1",            72 , 118, 255},
    {"RoyalBlue2",            67 , 110, 238},
    {"RoyalBlue3",            58 , 95 , 205},
    {"RoyalBlue4",            39 , 64 , 139},
    {"blue1",                 0  , 0  , 255},
    {"blue2",                 0  , 0  , 238},
    {"blue3",                 0  , 0  , 205},
    {"blue4",                 0  , 0  , 139},
    {"DodgerBlue1",           30 , 144, 255},
    {"DodgerBlue2",           28 , 134, 238},
    {"DodgerBlue3",           24 , 116, 205},
    {"DodgerBlue4",           16 , 78 , 139},
    {"SteelBlue1",            99 , 184, 255},
    {"SteelBlue2",            92 , 172, 238},
    {"SteelBlue3",            79 , 148, 205},
    {"SteelBlue4",            54 , 100, 139},
    {"DeepSkyBlue1",          0  , 191, 255},
    {"DeepSkyBlue2",          0  , 178, 238},
    {"DeepSkyBlue3",          0  , 154, 205},
    {"DeepSkyBlue4",          0  , 104, 139},
    {"SkyBlue1",              135, 206, 255},
    {"SkyBlue2",              126, 192, 238},
    {"SkyBlue3",              108, 166, 205},
    {"SkyBlue4",              74 , 112, 139},
    {"LightSkyBlue1",         176, 226, 255},
    {"LightSkyBlue2",         164, 211, 238},
    {"LightSkyBlue3",         141, 182, 205},
    {"LightSkyBlue4",         96 , 123, 139},
    {"SlateGray1",            198, 226, 255},
    {"SlateGray2",            185, 211, 238},
    {"SlateGray3",            159, 182, 205},
    {"SlateGray4",            108, 123, 139},
    {"LightSteelBlue1",       202, 225, 255},
    {"LightSteelBlue2",       188, 210, 238},
    {"LightSteelBlue3",       162, 181, 205},
    {"LightSteelBlue4",       110, 123, 139},
    {"LightBlue1",            191, 239, 255},
    {"LightBlue2",            178, 223, 238},
    {"LightBlue3",            154, 192, 205},
    {"LightBlue4",            104, 131, 139},
    {"LightCyan1",            224, 255, 255},
    {"LightCyan2",            209, 238, 238},
    {"LightCyan3",            180, 205, 205},
    {"LightCyan4",            122, 139, 139},
    {"PaleTurquoise1",        187, 255, 255},
    {"PaleTurquoise2",        174, 238, 238},
    {"PaleTurquoise3",        150, 205, 205},
    {"PaleTurquoise4",        102, 139, 139},
    {"CadetBlue1",            152, 245, 255},
    {"CadetBlue2",            142, 229, 238},
    {"CadetBlue3",            122, 197, 205},
    {"CadetBlue4",            83 , 134, 139},
    {"turquoise1",            0  , 245, 255},
    {"turquoise2",            0  , 229, 238},
    {"turquoise3",            0  , 197, 205},
    {"turquoise4",            0  , 134, 139},
    {"cyan1",                 0  , 255, 255},
    {"cyan2",                 0  , 238, 238},
    {"cyan3",                 0  , 205, 205},
    {"cyan4",                 0  , 139, 139},
    {"DarkSlateGray1",        151, 255, 255},
    {"DarkSlateGray2",        141, 238, 238},
    {"DarkSlateGray3",        121, 205, 205},
    {"DarkSlateGray4",        82 , 139, 139},
    {"aquamarine1",           127, 255, 212},
    {"aquamarine2",           118, 238, 198},
    {"aquamarine3",           102, 205, 170},
    {"aquamarine4",           69 , 139, 116},
    {"DarkSeaGreen1",         193, 255, 193},
    {"DarkSeaGreen2",         180, 238, 180},
    {"DarkSeaGreen3",         155, 205, 155},
    {"DarkSeaGreen4",         105, 139, 105},
    {"SeaGreen1",             84 , 255, 159},
    {"SeaGreen2",             78 , 238, 148},
    {"SeaGreen3",             67 , 205, 128},
    {"SeaGreen4",             46 , 139, 87 },
    {"PaleGreen1",            154, 255, 154},
    {"PaleGreen2",            144, 238, 144},
    {"PaleGreen3",            124, 205, 124},
    {"PaleGreen4",            84 , 139, 84 },
    {"SpringGreen1",          0  , 255, 127},
    {"SpringGreen2",          0  , 238, 118},
    {"SpringGreen3",          0  , 205, 102},
    {"SpringGreen4",          0  , 139, 69 },
    {"green1",                0  , 255, 0  },
    {"green2",                0  , 238, 0  },
    {"green3",                0  , 205, 0  },
    {"green4",                0  , 139, 0  },
    {"chartreuse1",           127, 255, 0  },
    {"chartreuse2",           118, 238, 0  },
    {"chartreuse3",           102, 205, 0  },
    {"chartreuse4",           69 , 139, 0  },
    {"OliveDrab1",            192, 255, 62 },
    {"OliveDrab2",            179, 238, 58 },
    {"OliveDrab3",            154, 205, 50 },
    {"OliveDrab4",            105, 139, 34 },
    {"DarkOliveGreen1",       202, 255, 112},
    {"DarkOliveGreen2",       188, 238, 104},
    {"DarkOliveGreen3",       162, 205, 90 },
    {"DarkOliveGreen4",       110, 139, 61 },
    {"khaki1",                255, 246, 143},
    {"khaki2",                238, 230, 133},
    {"khaki3",                205, 198, 115},
    {"khaki4",                139, 134, 78 },
    {"LightGoldenrod1",       255, 236, 139},
    {"LightGoldenrod2",       238, 220, 130},
    {"LightGoldenrod3",       205, 190, 112},
    {"LightGoldenrod4",       139, 129, 76 },
    {"LightYellow1",          255, 255, 224},
    {"LightYellow2",          238, 238, 209},
    {"LightYellow3",          205, 205, 180},
    {"LightYellow4",          139, 139, 122},
    {"yellow1",               255, 255, 0  },
    {"yellow2",               238, 238, 0  },
    {"yellow3",               205, 205, 0  },
    {"yellow4",               139, 139, 0  },
    {"gold1",                 255, 215, 0  },
    {"gold2",                 238, 201, 0  },
    {"gold3",                 205, 173, 0  },
    {"gold4",                 139, 117, 0  },
    {"goldenrod1",            255, 193, 37 },
    {"goldenrod2",            238, 180, 34 },
    {"goldenrod3",            205, 155, 29 },
    {"goldenrod4",            139, 105, 20 },
    {"DarkGoldenrod1",        255, 185, 15 },
    {"DarkGoldenrod2",        238, 173, 14 },
    {"DarkGoldenrod3",        205, 149, 12 },
    {"DarkGoldenrod4",        139, 101, 8  },
    {"RosyBrown1",            255, 193, 193},
    {"RosyBrown2",            238, 180, 180},
    {"RosyBrown3",            205, 155, 155},
    {"RosyBrown4",            139, 105, 105},
    {"IndianRed1",            255, 106, 106},
    {"IndianRed2",            238, 99 , 99 },
    {"IndianRed3",            205, 85 , 85 },
    {"IndianRed4",            139, 58 , 58 },
    {"sienna1",               255, 130, 71 },
    {"sienna2",               238, 121, 66 },
    {"sienna3",               205, 104, 57 },
    {"sienna4",               139, 71 , 38 },
    {"burlywood1",            255, 211, 155},
    {"burlywood2",            238, 197, 145},
    {"burlywood3",            205, 170, 125},
    {"burlywood4",            139, 115, 85 },
    {"wheat1",                255, 231, 186},
    {"wheat2",                238, 216, 174},
    {"wheat3",                205, 186, 150},
    {"wheat4",                139, 126, 102},
    {"tan1",                  255, 165, 79 },
    {"tan2",                  238, 154, 73 },
    {"tan3",                  205, 133, 63 },
    {"tan4",                  139, 90 , 43 },
    {"chocolate1",            255, 127, 36 },
    {"chocolate2",            238, 118, 33 },
    {"chocolate3",            205, 102, 29 },
    {"chocolate4",            139, 69 , 19 },
    {"firebrick1",            255, 48 , 48 },
    {"firebrick2",            238, 44 , 44 },
    {"firebrick3",            205, 38 , 38 },
    {"firebrick4",            139, 26 , 26 },
    {"brown1",                255, 64 , 64 },
    {"brown2",                238, 59 , 59 },
    {"brown3",                205, 51 , 51 },
    {"brown4",                139, 35 , 35 },
    {"salmon1",               255, 140, 105},
    {"salmon2",               238, 130, 98 },
    {"salmon3",               205, 112, 84 },
    {"salmon4",               139, 76 , 57 },
    {"LightSalmon1",          255, 160, 122},
    {"LightSalmon2",          238, 149, 114},
    {"LightSalmon3",          205, 129, 98 },
    {"LightSalmon4",          139, 87 , 66 },
    {"orange1",               255, 165, 0  },
    {"orange2",               238, 154, 0  },
    {"orange3",               205, 133, 0  },
    {"orange4",               139, 90 , 0  },
    {"DarkOrange1",           255, 127, 0  },
    {"DarkOrange2",           238, 118, 0  },
    {"DarkOrange3",           205, 102, 0  },
    {"DarkOrange4",           139, 69 , 0  },
    {"coral1",                255, 114, 86 },
    {"coral2",                238, 106, 80 },
    {"coral3",                205, 91 , 69 },
    {"coral4",                139, 62 , 47 },
    {"tomato1",               255, 99 , 71 },
    {"tomato2",               238, 92 , 66 },
    {"tomato3",               205, 79 , 57 },
    {"tomato4",               139, 54 , 38 },
    {"OrangeRed1",            255, 69 , 0  },
    {"OrangeRed2",            238, 64 , 0  },
    {"OrangeRed3",            205, 55 , 0  },
    {"OrangeRed4",            139, 37 , 0  },
    {"red1",                  255, 0  , 0  },
    {"red2",                  238, 0  , 0  },
    {"red3",                  205, 0  , 0  },
    {"red4",                  139, 0  , 0  },
    {"DeepPink1",             255, 20 , 147},
    {"DeepPink2",             238, 18 , 137},
    {"DeepPink3",             205, 16 , 118},
    {"DeepPink4",             139, 10 , 80 },
    {"HotPink1",              255, 110, 180},
    {"HotPink2",              238, 106, 167},
    {"HotPink3",              205, 96 , 144},
    {"HotPink4",              139, 58 , 98 },
    {"pink1",                 255, 181, 197},
    {"pink2",                 238, 169, 184},
    {"pink3",                 205, 145, 158},
    {"pink4",                 139, 99 , 108},
    {"LightPink1",            255, 174, 185},
    {"LightPink2",            238, 162, 173},
    {"LightPink3",            205, 140, 149},
    {"LightPink4",            139, 95 , 101},
    {"PaleVioletRed1",        255, 130, 171},
    {"PaleVioletRed2",        238, 121, 159},
    {"PaleVioletRed3",        205, 104, 137},
    {"PaleVioletRed4",        139, 71 , 93 },
    {"maroon1",               255, 52 , 179},
    {"maroon2",               238, 48 , 167},
    {"maroon3",               205, 41 , 144},
    {"maroon4",               139, 28 , 98 },
    {"VioletRed1",            255, 62 , 150},
    {"VioletRed2",            238, 58 , 140},
    {"VioletRed3",            205, 50 , 120},
    {"VioletRed4",            139, 34 , 82 },
    {"magenta1",              255, 0  , 255},
    {"magenta2",              238, 0  , 238},
    {"magenta3",              205, 0  , 205},
    {"magenta4",              139, 0  , 139},
    {"orchid1",               255, 131, 250},
    {"orchid2",               238, 122, 233},
    {"orchid3",               205, 105, 201},
    {"orchid4",               139, 71 , 137},
    {"plum1",                 255, 187, 255},
    {"plum2",                 238, 174, 238},
    {"plum3",                 205, 150, 205},
    {"plum4",                 139, 102, 139},
    {"MediumOrchid1",         224, 102, 255},
    {"MediumOrchid2",         209, 95 , 238},
    {"MediumOrchid3",         180, 82 , 205},
    {"MediumOrchid4",         122, 55 , 139},
    {"DarkOrchid1",           191, 62 , 255},
    {"DarkOrchid2",           178, 58 , 238},
    {"DarkOrchid3",           154, 50 , 205},
    {"DarkOrchid4",           104, 34 , 139},
    {"purple1",               155, 48 , 255},
    {"purple2",               145, 44 , 238},
    {"purple3",               125, 38 , 205},
    {"purple4",               85 , 26 , 139},
    {"MediumPurple1",         171, 130, 255},
    {"MediumPurple2",         159, 121, 238},
    {"MediumPurple3",         137, 104, 205},
    {"MediumPurple4",         93 , 71 , 139},
    {"thistle1",              255, 225, 255},
    {"thistle2",              238, 210, 238},
    {"thistle3",              205, 181, 205},
    {"thistle4",              139, 123, 139},
    {"gray0",                 0  , 0  , 0  },
    {"grey0",                 0  , 0  , 0  },
    {"gray1",                 3  , 3  , 3  },
    {"grey1",                 3  , 3  , 3  },
    {"gray2",                 5  , 5  , 5  },
    {"grey2",                 5  , 5  , 5  },
    {"gray3",                 8  , 8  , 8  },
    {"grey3",                 8  , 8  , 8  },
    {"gray4",                 10 , 10 , 10 },
    {"grey4",                 10 , 10 , 10 },
    {"gray5",                 13 , 13 , 13 },
    {"grey5",                 13 , 13 , 13 },
    {"gray6",                 15 , 15 , 15 },
    {"grey6",                 15 , 15 , 15 },
    {"gray7",                 18 , 18 , 18 },
    {"grey7",                 18 , 18 , 18 },
    {"gray8",                 20 , 20 , 20 },
    {"grey8",                 20 , 20 , 20 },
    {"gray9",                 23 , 23 , 23 },
    {"grey9",                 23 , 23 , 23 },
    {"gray10",                26 , 26 , 26 },
    {"grey10",                26 , 26 , 26 },
    {"gray11",                28 , 28 , 28 },
    {"grey11",                28 , 28 , 28 },
    {"gray12",                31 , 31 , 31 },
    {"grey12",                31 , 31 , 31 },
    {"gray13",                33 , 33 , 33 },
    {"grey13",                33 , 33 , 33 },
    {"gray14",                36 , 36 , 36 },
    {"grey14",                36 , 36 , 36 },
    {"gray15",                38 , 38 , 38 },
    {"grey15",                38 , 38 , 38 },
    {"gray16",                41 , 41 , 41 },
    {"grey16",                41 , 41 , 41 },
    {"gray17",                43 , 43 , 43 },
    {"grey17",                43 , 43 , 43 },
    {"gray18",                46 , 46 , 46 },
    {"grey18",                46 , 46 , 46 },
    {"gray19",                48 , 48 , 48 },
    {"grey19",                48 , 48 , 48 },
    {"gray20",                51 , 51 , 51 },
    {"grey20",                51 , 51 , 51 },
    {"gray21",                54 , 54 , 54 },
    {"grey21",                54 , 54 , 54 },
    {"gray22",                56 , 56 , 56 },
    {"grey22",                56 , 56 , 56 },
    {"gray23",                59 , 59 , 59 },
    {"grey23",                59 , 59 , 59 },
    {"gray24",                61 , 61 , 61 },
    {"grey24",                61 , 61 , 61 },
    {"gray25",                64 , 64 , 64 },
    {"grey25",                64 , 64 , 64 },
    {"gray26",                66 , 66 , 66 },
    {"grey26",                66 , 66 , 66 },
    {"gray27",                69 , 69 , 69 },
    {"grey27",                69 , 69 , 69 },
    {"gray28",                71 , 71 , 71 },
    {"grey28",                71 , 71 , 71 },
    {"gray29",                74 , 74 , 74 },
    {"grey29",                74 , 74 , 74 },
    {"gray30",                77 , 77 , 77 },
    {"grey30",                77 , 77 , 77 },
    {"gray31",                79 , 79 , 79 },
    {"grey31",                79 , 79 , 79 },
    {"gray32",                82 , 82 , 82 },
    {"grey32",                82 , 82 , 82 },
    {"gray33",                84 , 84 , 84 },
    {"grey33",                84 , 84 , 84 },
    {"gray34",                87 , 87 , 87 },
    {"grey34",                87 , 87 , 87 },
    {"gray35",                89 , 89 , 89 },
    {"grey35",                89 , 89 , 89 },
    {"gray36",                92 , 92 , 92 },
    {"grey36",                92 , 92 , 92 },
    {"gray37",                94 , 94 , 94 },
    {"grey37",                94 , 94 , 94 },
    {"gray38",                97 , 97 , 97 },
    {"grey38",                97 , 97 , 97 },
    {"gray39",                99 , 99 , 99 },
    {"grey39",                99 , 99 , 99 },
    {"gray40",                102, 102, 102},
    {"grey40",                102, 102, 102},
    {"gray41",                105, 105, 105},
    {"grey41",                105, 105, 105},
    {"gray42",                107, 107, 107},
    {"grey42",                107, 107, 107},
    {"gray43",                110, 110, 110},
    {"grey43",                110, 110, 110},
    {"gray44",                112, 112, 112},
    {"grey44",                112, 112, 112},
    {"gray45",                115, 115, 115},
    {"grey45",                115, 115, 115},
    {"gray46",                117, 117, 117},
    {"grey46",                117, 117, 117},
    {"gray47",                120, 120, 120},
    {"grey47",                120, 120, 120},
    {"gray48",                122, 122, 122},
    {"grey48",                122, 122, 122},
    {"gray49",                125, 125, 125},
    {"grey49",                125, 125, 125},
    {"gray50",                127, 127, 127},
    {"grey50",                127, 127, 127},
    {"gray51",                130, 130, 130},
    {"grey51",                130, 130, 130},
    {"gray52",                133, 133, 133},
    {"grey52",                133, 133, 133},
    {"gray53",                135, 135, 135},
    {"grey53",                135, 135, 135},
    {"gray54",                138, 138, 138},
    {"grey54",                138, 138, 138},
    {"gray55",                140, 140, 140},
    {"grey55",                140, 140, 140},
    {"gray56",                143, 143, 143},
    {"grey56",                143, 143, 143},
    {"gray57",                145, 145, 145},
    {"grey57",                145, 145, 145},
    {"gray58",                148, 148, 148},
    {"grey58",                148, 148, 148},
    {"gray59",                150, 150, 150},
    {"grey59",                150, 150, 150},
    {"gray60",                153, 153, 153},
    {"grey60",                153, 153, 153},
    {"gray61",                156, 156, 156},
    {"grey61",                156, 156, 156},
    {"gray62",                158, 158, 158},
    {"grey62",                158, 158, 158},
    {"gray63",                161, 161, 161},
    {"grey63",                161, 161, 161},
    {"gray64",                163, 163, 163},
    {"grey64",                163, 163, 163},
    {"gray65",                166, 166, 166},
    {"grey65",                166, 166, 166},
    {"gray66",                168, 168, 168},
    {"grey66",                168, 168, 168},
    {"gray67",                171, 171, 171},
    {"grey67",                171, 171, 171},
    {"gray68",                173, 173, 173},
    {"grey68",                173, 173, 173},
    {"gray69",                176, 176, 176},
    {"grey69",                176, 176, 176},
    {"gray70",                179, 179, 179},
    {"grey70",                179, 179, 179},
    {"gray71",                181, 181, 181},
    {"grey71",                181, 181, 181},
    {"gray72",                184, 184, 184},
    {"grey72",                184, 184, 184},
    {"gray73",                186, 186, 186},
    {"grey73",                186, 186, 186},
    {"gray74",                189, 189, 189},
    {"grey74",                189, 189, 189},
    {"gray75",                191, 191, 191},
    {"grey75",                191, 191, 191},
    {"gray76",                194, 194, 194},
    {"grey76",                194, 194, 194},
    {"gray77",                196, 196, 196},
    {"grey77",                196, 196, 196},
    {"gray78",                199, 199, 199},
    {"grey78",                199, 199, 199},
    {"gray79",                201, 201, 201},
    {"grey79",                201, 201, 201},
    {"gray80",                204, 204, 204},
    {"grey80",                204, 204, 204},
    {"gray81",                207, 207, 207},
    {"grey81",                207, 207, 207},
    {"gray82",                209, 209, 209},
    {"grey82",                209, 209, 209},
    {"gray83",                212, 212, 212},
    {"grey83",                212, 212, 212},
    {"gray84",                214, 214, 214},
    {"grey84",                214, 214, 214},
    {"gray85",                217, 217, 217},
    {"grey85",                217, 217, 217},
    {"gray86",                219, 219, 219},
    {"grey86",                219, 219, 219},
    {"gray87",                222, 222, 222},
    {"grey87",                222, 222, 222},
    {"gray88",                224, 224, 224},
    {"grey88",                224, 224, 224},
    {"gray89",                227, 227, 227},
    {"grey89",                227, 227, 227},
    {"gray90",                229, 229, 229},
    {"grey90",                229, 229, 229},
    {"gray91",                232, 232, 232},
    {"grey91",                232, 232, 232},
    {"gray92",                235, 235, 235},
    {"grey92",                235, 235, 235},
    {"gray93",                237, 237, 237},
    {"grey93",                237, 237, 237},
    {"gray94",                240, 240, 240},
    {"grey94",                240, 240, 240},
    {"gray95",                242, 242, 242},
    {"grey95",                242, 242, 242},
    {"gray96",                245, 245, 245},
    {"grey96",                245, 245, 245},
    {"gray97",                247, 247, 247},
    {"grey97",                247, 247, 247},
    {"gray98",                250, 250, 250},
    {"grey98",                250, 250, 250},
    {"gray99",                252, 252, 252},
    {"grey99",                252, 252, 252},
    {"gray100",               255, 255, 255},
    {"grey100",               255, 255, 255},
    {"dark grey",             169, 169, 169},
    {"DarkGrey",              169, 169, 169},
    {"dark gray",             169, 169, 169},
    {"DarkGray",              169, 169, 169},
    {"dark blue",             0  , 0  , 139},
    {"DarkBlue",              0  , 0  , 139},
    {"dark cyan",             0  , 139, 139},
    {"DarkCyan",              0  , 139, 139},
    {"dark magenta",          139, 0  , 139},
    {"DarkMagenta",           139, 0  , 139},
    {"dark red",              139, 0  , 0  },
    {"DarkRed",               139, 0  , 0  },
    {"light green",           144, 238, 144},
    {"LightGreen",            144, 238, 144},
    {"crimson",               220, 20 , 60 },
    {"indigo",                75 , 0  , 130},
    {"olive",                 128, 128, 0  },
    {"rebecca purple",        102, 51 , 153},
    {"RebeccaPurple",         102, 51 , 153},
    {"silver",                192, 192, 192},
    {"teal",                  0  , 128, 128},
    {0,                       0  , 0  , 0  }   /* end of list */
};

/*
 * The numbers below are 3-bit colour codes for the OS/2 console
 *    +---+---+---+
 *    | R | G | B |
 *    +---+---+---+
 *      1   0   0    = 4, Red
 * See the comment in ckocon.h near swapcolors for a full description.
 */
static
unsigned char sgrcols[8] = {
/* Black   */ 0,    /* 0 (index) */
/* Red     */ 4,    /* 1 */
/* Green   */ 2,    /* 2 */
/* Brown   */ 6,    /* 3 */
/* Blue    */ 1,    /* 4 */
/* Magenta */ 5,    /* 5 */
/* Cyan    */ 3,    /* 6 */
/* White   */ 7     /* 7 */
};

/* Map colour code (table above) back to SGR Index */
static unsigned char sgrindex[8] = {
    0,
    4,
    2,
    6,
    1,
    5,
    3,
    7
};

#ifdef COMMENT
/* Not used but perhaps useful, commented out -- DG */
static
unsigned char isocols[8] = {
/* Black   */ 0,
/* Blue    */ 1,
/* Green   */ 2,
/* Cyan    */ 3,
/* Red     */ 4,
/* Magenta */ 5,
/* Yellow  */ 6,
/* White   */ 7
};
#endif /* COMMENT */

/* Function prototypes */
#ifndef NOTTOCI
int ttoci(char c);
#endif /* NOTTOCI */

int status_saved = -1;

extern int os2_outesc ;                     /* Esc seq recognizer for keys... */

/* BA80 Function Key Label Reader */
static char *ba80_fkey_ptr=NULL;
static int  ba80_fkey_read = 0;

/* VTNT variables */

#define VTNT_BUFSZ      36864
#define VTNT_MIN_READ   42
static char vtnt_buf[VTNT_BUFSZ]="";
static unsigned long  vtnt_index = 0;
static unsigned long  vtnt_read  = VTNT_MIN_READ;

/* DEC F-key strings */
char * fkeys[] = {
 "[11~","[12~","[13~","[14~","[15~",    /* F1  - F5 PC Keyboard */
 "[17~","[18~","[19~","[20~","[21~",    /* F6  - F10 */
 "[23~","[24~","[25~","[26~","[28~",    /* F11 - F15 */
 "[29~","[31~","[32~","[33~","[34~"     /* F16 - F20 */
};

/* DEC Editing key strings */
char * ekeys[] = {
    "[1~",      /* Find */
    "[2~",      /* Insert */
    "[3~",      /* Remove */
    "[4~",      /* Select */
    "[5~",      /* Previous Screen */
    "[6~",      /* Next Screen */
    "[H"        /* PC Home */
};

/* DEC User Defined Key strings */
/* Also used for SCO ANSI UDK strings */
/* There are 15 DEC strings, and 60 AT386 strings */
/* And 65 Wyse characters */
/* And close to 108 DG keys (regular and unix modes) */
/* 153 SNI 97801 keys */
char * udkfkeys[200];  /* let udkreset() initialize them */
int udklock = 0 ;      /* Are User Defined Keys locked? */

#ifndef NOKVERBS
extern struct keytab kverbs[] ;         /* Kverbs table  */
extern int nkverbs ;                    /* Num of Kverbs */

/* Compose-key support structures and tables */

struct compose_key_tab {
    CHAR c1;                            /* First char of compose sequence */
    CHAR c2;                            /* Second char of compose sequence */
    CHAR c3;                            /* Character that it maps to */
};

struct compose_key_tab l1ktab[] = {     /* The Latin-1 Compose Key Table */
    'N', 'B', (CHAR) 0xA0,		/* No-Break Space */
    'n', 'b', (CHAR) 0xA0,		/* No-Break Space */
    'A', '`', (CHAR) 0xC0,              /* A grave */
    '`', 'A', (CHAR) 0xC0,              /* A grave */
    'A', (CHAR) 0x27, (CHAR) 0xC1,      /* A acute */
    (CHAR) 0x27, 'A', (CHAR) 0xC1,      /* A acute */
    'A', '^', (CHAR) 0xC2,              /* A circumflex */
    '^', 'A', (CHAR) 0xC2,              /* A circumflex */
    'A', '~', (CHAR) 0xC3,              /* A tilde */
    '~', 'A', (CHAR) 0xC3,              /* A tilde */
    'A', '"', (CHAR) 0xC4,              /* A diaeresis */
    '"', 'A', (CHAR) 0xC4,              /* A diaeresis */
    'A', '*', (CHAR) 0xC5,              /* A ring above */
    '*', 'A', (CHAR) 0xC5,              /* A ring above */
    'A', 'E', (CHAR) 0xC6,              /* A with E */
    'C', ',', (CHAR) 0xC7,              /* C Cedilla */
    ',', 'C', (CHAR) 0xC7,              /* C Cedilla */
    'E', '`', (CHAR) 0xC8,              /* E grave */
    '`', 'E', (CHAR) 0xC8,              /* E grave */
    'E', (CHAR) 0x27, (CHAR) 0xC9,      /* E acute */
    (CHAR) 0x27, 'E', (CHAR) 0xC9,      /* E acute */
    'E', '^', (CHAR) 0xCA,              /* E circumflex */
    '^', 'E', (CHAR) 0xCA,              /* E circumflex */
    'E', '"', (CHAR) 0xCB,              /* E diaeresis */
    '"', 'E', (CHAR) 0xCB,              /* E diaeresis */
    'I', '`', (CHAR) 0xCC,              /* I grave */
    '`', 'I', (CHAR) 0xCC,              /* I grave */
    'I', (CHAR) 0x27, (CHAR) 0xCD,      /* I acute */
    (CHAR) 0x27, 'I', (CHAR) 0xCD,      /* I acute */
    'I', '^', (CHAR) 0xCE,              /* I circumflex */
    '^', 'I', (CHAR) 0xCE,              /* I circumflex */
    'I', '"', (CHAR) 0xCF,              /* I diaeresis */
    '"', 'I', (CHAR) 0xCF,              /* I diaeresis */
    '-', 'D', (CHAR) 0xD0,              /* Icelandic Eth */
    'D', '-', (CHAR) 0xD0,              /* Icelandic Eth */
    'N', '~', (CHAR) 0xD1,              /* N tilde */
    '~', 'N', (CHAR) 0xD1,              /* N tilde */
    'O', 'E', (CHAR) 0xD7,      /* OE digraph (not really in Latin-1) */
    'O', '`', (CHAR) 0xD2,              /* O grave */
    '`', 'O', (CHAR) 0xD2,              /* O grave */
    'O', (CHAR) 0x27, (CHAR) 0xD3,      /* O acute */
    (CHAR) 0x27, 'O', (CHAR) 0xD3,      /* O acute */
    'O', '^', (CHAR) 0xD4,              /* O circumflex */
    '^', 'O', (CHAR) 0xD4,              /* O circumflex */
    'O', '~', (CHAR) 0xD5,              /* O tilde */
    '~', 'O', (CHAR) 0xD5,              /* O tilde */
    'O', '"', (CHAR) 0xD6,              /* O diaeresis */
    '"', 'O', (CHAR) 0xD6,              /* O diaeresis */
    'O', '/', (CHAR) 0xD8,              /* O oblique stroke */
    '/', 'O', (CHAR) 0xD8,              /* O oblique stroke */
    'U', '`', (CHAR) 0xD9,              /* U grave */
    '`', 'U', (CHAR) 0xD9,              /* U grave */
    'U', (CHAR) 0x27, (CHAR) 0xDA,      /* U acute */
    (CHAR) 0x27, 'U', (CHAR) 0xDA,      /* U acute */
    'U', '^', (CHAR) 0xDB,              /* U circumflex */
    '^', 'U', (CHAR) 0xDB,              /* U circumflex */
    'U', '"', (CHAR) 0xDC,              /* U diaeresis */
    '"', 'U', (CHAR) 0xDC,              /* U diaeresis */
    'Y', (CHAR) 0x27, (CHAR) 0xDD,      /* Y acute */
    (CHAR) 0x27, 'Y', (CHAR) 0xDD,      /* Y acute */
    'H', 'T', (CHAR) 0xDE,              /* Icelandic Thorn */
    'T', 'H', (CHAR) 0xDE,              /* Icelandic Thorn */
    's', 's', (CHAR) 0xDF,              /* German scharfes s */
    'a', '`', (CHAR) 0xE0,              /* a grave */
    '`', 'a', (CHAR) 0xE0,              /* a grave */
    'a', (CHAR) 0x27, (CHAR) 0xE1,      /* a acute */
    (CHAR) 0x27, 'a', (CHAR) 0xE1,      /* a acute */
    'a', '^', (CHAR) 0xE2,              /* a circumflex */
    '^', 'a', (CHAR) 0xE2,              /* a circumflex */
    'a', '~', (CHAR) 0xE3,              /* a tilde */
    '~', 'a', (CHAR) 0xE3,              /* a tilde */
    'a', '"', (CHAR) 0xE4,              /* a diaeresis */
    '"', 'a', (CHAR) 0xE4,              /* a diaeresis */
    'a', '*', (CHAR) 0xE5,              /* a ring above */
    '*', 'a', (CHAR) 0xE5,              /* a ring above */
    'a', 'e', (CHAR) 0xE6,              /* a with e */
    'c', ',', (CHAR) 0xE7,              /* c cedilla */
    ',', 'c', (CHAR) 0xE7,              /* c cedilla */
    'e', '`', (CHAR) 0xE8,              /* e grave */
    '`', 'e', (CHAR) 0xE8,              /* e grave */
    'e', (CHAR) 0x27, (CHAR) 0xE9,      /* e acute */
    (CHAR) 0x27, 'e', (CHAR) 0xE9,      /* e acute */
    'e', '^', (CHAR) 0xEA,              /* e circumflex */
    '^', 'e', (CHAR) 0xEA,              /* e circumflex */
    'e', '"', (CHAR) 0xEB,              /* e diaeresis */
    '"', 'e', (CHAR) 0xEB,              /* e diaeresis */
    'i', '`', (CHAR) 0xEC,              /* i grave */
    '`', 'i', (CHAR) 0xEC,              /* i grave */
    'i', (CHAR) 0x27, (CHAR) 0xED,      /* i acute */
    (CHAR) 0x27, 'i', (CHAR) 0xED,      /* i acute */
    'i', '^', (CHAR) 0xEE,              /* i circumflex */
    '^', 'i', (CHAR) 0xEE,              /* i circumflex */
    'i', '"', (CHAR) 0xEF,              /* i diaeresis */
    '"', 'i', (CHAR) 0xEF,              /* i diaeresis */
    '-', 'd', (CHAR) 0xF0,              /* Icelandic eth */
    'd', '-', (CHAR) 0xF0,              /* Icelandic eth */
    'n', '~', (CHAR) 0xF1,              /* n tilde */
    '~', 'n', (CHAR) 0xF1,              /* n tilde */
    'o', 'e', (CHAR) 0xF7,      /* oe digraph (not really in Latin-1) */
    'o', '`', (CHAR) 0xF2,              /* o grave */
    '`', 'o', (CHAR) 0xF2,              /* o grave */
    'o', (CHAR) 0x27, (CHAR) 0xF3,      /* o acute */
    (CHAR) 0x27, 'o', (CHAR) 0xF3,      /* o acute */
    'o', '^', (CHAR) 0xF4,              /* o circumflex */
    '^', 'o', (CHAR) 0xF4,              /* o circumflex */
    'o', '~', (CHAR) 0xF5,              /* o tilde */
    '~', 'o', (CHAR) 0xF5,              /* o tilde */
    'o', '"', (CHAR) 0xF6,              /* o diaeresis */
    '"', 'o', (CHAR) 0xF6,              /* o diaeresis */
    '-', ':', (CHAR) 0xF7,              /* Division sign */
    'o', '/', (CHAR) 0xF8,              /* o oblique stroke */
    '/', 'o', (CHAR) 0xF8,              /* o oblique stroke */
    'u', '`', (CHAR) 0xF9,              /* u grave */
    '`', 'u', (CHAR) 0xF9,              /* u grave */
    'u', (CHAR) 0x27, (CHAR) 0xFA,      /* u acute */
    (CHAR) 0x27, 'u', (CHAR) 0xFA,      /* u acute */
    'u', '^', (CHAR) 0xFB,              /* u circumflex */
    '^', 'u', (CHAR) 0xFB,              /* u circumflex */
    'u', '"', (CHAR) 0xFC,              /* u diaeresis */
    '"', 'u', (CHAR) 0xFC,              /* u diaeresis */
    'y', (CHAR) 0x27, (CHAR) 0xFD,      /* y acute */
    (CHAR) 0x27, 'y', (CHAR) 0xFD,      /* y acute */
    'h', 't', (CHAR) 0xFE,              /* Icelandic thorn */
    't', 'h', (CHAR) 0xFE,              /* Icelandic thorn */
    'y', '"', (CHAR) 0xFF,              /* y diaeresis */
    '"', 'y', (CHAR) 0xFF,              /* y diaeresis */
    '+', '+', '#',                      /* Number sign */
    'A', 'A', '@',                      /* At sign */
    'a', 'a', '@',                      /* At sign */
    '(', '(', '[',                      /* Left bracket */
    '/', '/', '\\',                     /* Backslash */
    '/', '<', '\\',                     /* Backslash */
    ')', ')', ']',                      /* Right bracket */
    '(', '-', '{',                      /* Left brace */
    '/', '^', '|',                      /* Vertical bar */
    ')', '-', '}',                      /* Right brace */
    '!', '!', (CHAR) 0xA1,              /* Inverted exclamation */
    'C', '/', (CHAR) 0xA2,              /* Cent sign */
    'c', '/', (CHAR) 0xA2,              /* Cent sign */
    'L', '-', (CHAR) 0xA3,              /* Pound sterling sign */
    'l', '-', (CHAR) 0xA3,              /* Pound sterling sign */
    'Y', '-', (CHAR) 0xA5,              /* Yen sign */
    'y', '-', (CHAR) 0xA5,              /* Yen sign */
    '|', '|', (CHAR) 0xA6,              /* Broken bar */
    'S', 'O', (CHAR) 0xA7,              /* Paragraph sign */
    'S', '!', (CHAR) 0xA7,              /* Paragraph sign */
    'S', '0', (CHAR) 0xA7,              /* Paragraph sign */
    's', 'o', (CHAR) 0xA7,              /* Paragraph sign */
    's', '!', (CHAR) 0xA7,              /* Paragraph sign */
    's', '0', (CHAR) 0xA7,              /* Paragraph sign */
    'X', 'O', (CHAR) 0xA4,              /* Currency sign */
    'X', '0', (CHAR) 0xA4,              /* Currency sign */
    'x', 'o', (CHAR) 0xA4,              /* Currency sign */
    'x', '0', (CHAR) 0xA4,              /* Currency sign */
    'C', 'O', (CHAR) 0xA9,              /* Copyright sign */
    'C', '0', (CHAR) 0xA9,              /* Copyright sign */
    'c', 'o', (CHAR) 0xA9,              /* Copyright sign */
    'c', '0', (CHAR) 0xA9,              /* Copyright sign */
    'A', '_', (CHAR) 0xAA,              /* Feminine ordinal */
    'a', '_', (CHAR) 0xAA,              /* Feminine ordinal */
    '<', '<', (CHAR) 0xAB,              /* Left angle quotation */
    '-', ',', (CHAR) 0xAC,              /* Not sign */
    '-', '-', (CHAR) 0xAD,              /* Soft hyphen */
    'R', 'O', (CHAR) 0xAE,              /* Registered Trademark */
    'r', 'o', (CHAR) 0xAE,              /* Registered Trademark */
    '-', '^', (CHAR) 0xAF,              /* Macron */
    '0', '^', (CHAR) 0xB0,              /* Degree sign */
    '+', '-', (CHAR) 0xB1,              /* Plus or minus sign */
    '2', '^', (CHAR) 0xB2,              /* Superscript 2 */
    '3', '^', (CHAR) 0xB3,              /* Superscript 3 */
    (CHAR) 0x27, (CHAR) 0x27, (CHAR) 0xB4, /* Acute accent */
    '/', 'U', (CHAR) 0xB5,              /* Micro sign */
    'U', '/', (CHAR) 0xB5,              /* Micro sign */
    '/', 'u', (CHAR) 0xB5,              /* Micro sign */
    'u', '/', (CHAR) 0xB5,              /* Micro sign */
    'P', '!', (CHAR) 0xB6,              /* Pilcrow sign */
    'p', '!', (CHAR) 0xB6,              /* Pilcrow sign */
    '.', '^', (CHAR) 0xB7,              /* Middle dot */
    ',', ',', (CHAR) 0xB8,              /* Cedilla */
    '1', '^', (CHAR) 0xB9,              /* Superscript 1 */
    'O', '_', (CHAR) 0xBA,              /* Masculine ordinal */
    'o', '_', (CHAR) 0xBA,              /* Masculine ordinal */
    '>', '>', (CHAR) 0xBB,              /* Right angle quotation */
    '1', '4', (CHAR) 0xBC,              /* Fraction one quarter */
    '1', '2', (CHAR) 0xBD,              /* Fraction one half */
    '?', '?', (CHAR) 0xBF,              /* Inverted question mark */
    'x', 'x', (CHAR) 0xD7,              /* Multiplication sign */
    'X', 'X', (CHAR) 0xD7,              /* Multiplication sign */
    /*
    The following group is for entering ASCII characters that are otherwise
    impossible to enter, e.g. because they are dead-key combinations.
    */
    (CHAR)0x27, '.' ,(CHAR) 0x27,       /* Apostrophe */
    '.', (CHAR)0x27, (CHAR) 0x27,       /* Apostrophe */
    '^', '^', '^',                      /* Circumflex or caret */
    '`', '`', '`',                      /* Grave accent or backquote */
    '~', '~', '~',                      /* Tilde */
    ',', '.', ',',                      /* Comma */
    '.', ',', ',',                      /* Comma */
    '"', '"', '"',                      /* Doublequote */
    ':', ':', (CHAR) 0xA8               /* Diaeresis */

};
int nl1ktab = (sizeof(l1ktab) / sizeof(struct compose_key_tab));

struct compose_key_tab l2ktab[] = {     /* The Latin-2 Compose Key Table */
    'N', 'B', (CHAR) 0xA0,		/* No-Break Space */
    'A', C_OGONEK, (CHAR) 0xA1,         /* A ogonek */
    C_OGONEK, 'A', (CHAR) 0xA1,         /* A ogonek */
    C_BREVE, C_BREVE, (CHAR) 0xF4,      /* Breve */
    'L', '/', (CHAR) 0xA3,              /* L with stroke */
    '/', 'L', (CHAR) 0xA3,              /* L with stroke */
    'X', 'O', (CHAR) 0xA4,              /* Currency sign */
    'X', '0', (CHAR) 0xA4,              /* Currency sign */
    'x', 'o', (CHAR) 0xA4,              /* Currency sign */
    'x', '0', (CHAR) 0xA4,              /* Currency sign */
    'L', C_CARON, 0xA5,                 /* L caron */
    C_CARON, 'L', 0xA5,                 /* L caron */
    'S', C_ACUTE, (CHAR) 0xA6,          /* S acute */
    C_ACUTE, 'S', (CHAR) 0xA6,          /* S acute */
    'S', 'O', (CHAR) 0xA7,              /* Paragraph sign */
    'S', '!', (CHAR) 0xA7,              /* Paragraph sign */
    'S', '0', (CHAR) 0xA7,              /* Paragraph sign */
    's', 'o', (CHAR) 0xA7,              /* Paragraph sign */
    's', '!', (CHAR) 0xA7,              /* Paragraph sign */
    's', '0', (CHAR) 0xA7,              /* Paragraph sign */
    ':', ':', (CHAR) 0xA8,              /* Diaeresis */
    'S', C_CARON, (CHAR) 0xA9,          /* S caron */
    C_CARON, 'S', (CHAR) 0xA9,          /* S caron */
    'S', C_CEDILLA, (CHAR) 0xAA,        /* S cedilla */
    C_CEDILLA, 'S', (CHAR) 0xAA,        /* S cedilla */
    'T', C_CARON, (CHAR) 0xAB,          /* T caron */
    C_CARON, 'T', (CHAR) 0xAB,          /* T caron */
    'Z', C_ACUTE, (CHAR) 0xAC,          /* Z acute */
    C_ACUTE, 'Z', (CHAR) 0xAC,          /* Z acute */
    '-', '-', (CHAR) 0xAD,              /* Soft hyphen */
    'Z', C_CARON, (CHAR) 0xAE,          /* Z caron */
    C_CARON, 'Z', (CHAR) 0xAE,          /* Z caron */
    'Z', C_DOT, (CHAR) 0xAF,            /* Z dot above */
    C_DOT, 'Z', (CHAR) 0xAF,            /* Z dot above */
    '0', '^', (CHAR) 0xB0,              /* Degree sign */
    'a', C_OGONEK, (CHAR) 0xB1,         /* a ogonek */
    C_OGONEK, 'a', (CHAR) 0xB1,         /* a ogonek */
    C_OGONEK, C_OGONEK, (CHAR) 0xB2,    /* Ogonek */
    'l', '/', (CHAR) 0xB3,              /* l with stroke */
    '/', 'l',(CHAR) 0xB3,               /* l with stroke */
    C_ACUTE, C_ACUTE, (CHAR) 0xB4,      /* Acute accent */
    'l', C_CARON, (CHAR) 0xB5,          /* l caron */
    C_CARON, 'l', (CHAR) 0xB5,          /* l caron */
    's', C_ACUTE, (CHAR) 0xB6,          /* s acute */
    C_ACUTE, 's', (CHAR) 0xB6,          /* s acute */
    C_CARON, C_CARON, (CHAR) 0xB7,      /* Caron */
    C_CEDILLA, C_CEDILLA, (CHAR) 0xB8,  /* Cedilla */
    's', C_CARON, (CHAR) 0xB9,          /* s caron */
    C_CARON, 's', (CHAR) 0xB9,          /* s caron */
    's', C_CEDILLA, (CHAR) 0xBA,        /* s cedilla */
    C_CEDILLA, 's', (CHAR) 0xBA,        /* s cedilla */
    't', C_CARON, (CHAR) 0xBB,          /* t caron */
    C_CARON, 't', (CHAR) 0xBB,          /* t caron */
    'z', C_ACUTE, (CHAR) 0xBC,          /* z acute */
    C_ACUTE, 'z', (CHAR) 0xBC,          /* z acute */
    C_DACUTE, C_DACUTE, (CHAR) 0xBD,    /* Double acute */
    'z', C_CARON, (CHAR) 0xBE,          /* z caron */
    C_CARON, 'z', (CHAR) 0xBE,          /* z caron */
    'z', C_DOT, (CHAR) 0xBF,            /* z dot above */
    C_DOT, 'z', (CHAR) 0xBF,            /* z dot above */
    'R', C_ACUTE, (CHAR) 0xC0,          /* R acute */
    C_ACUTE, 'R', (CHAR) 0xC0,          /* R acute */
    'A', C_ACUTE, (CHAR) 0xC1,          /* A acute */
    C_ACUTE, 'A', (CHAR) 0xC1,          /* A acute */
    'A', '^', (CHAR) 0xC2,              /* A circumflex */
    '^', 'A', (CHAR) 0xC2,              /* A circumflex */
    'A', C_BREVE, (CHAR) 0xC3,          /* A breve */
    C_BREVE, 'A', (CHAR) 0xC3,          /* A breve */
    'A', '"', (CHAR) 0xC4,              /* A diaeresis */
    '"', 'A', (CHAR) 0xC4,              /* A diaeresis */
    'L', C_ACUTE, (CHAR) 0xC5,          /* L acute */
    C_ACUTE, 'L', (CHAR) 0xC5,          /* L acute */
    'C', C_ACUTE, (CHAR) 0xC6,          /* C acute */
    C_ACUTE, 'C', (CHAR) 0xC6,          /* C acute */
    'C', ',', (CHAR) 0xC7,              /* C cedilla */
    ',', 'C', (CHAR) 0xC7,              /* C cedilla */
    'C', C_CARON, (CHAR) 0xC8,          /* C caron */
    C_CARON, 'C', (CHAR) 0xC8,          /* C caron */
    'E', C_ACUTE, (CHAR) 0xC9,          /* E acute */
    C_ACUTE, 'E', (CHAR) 0xC9,          /* E acute */
    'E', C_OGONEK, (CHAR) 0xCA,         /* E ogonek */
    C_OGONEK, 'E', (CHAR) 0xCA,         /* E ogonek */
    'E', '"', (CHAR) 0xCB,              /* E diaeresis */
    '"', 'E', (CHAR) 0xCB,              /* E diaeresis */
    'E', C_CARON, (CHAR) 0xCC,          /* E caron */
    C_CARON, 'E', (CHAR) 0xCC,          /* E caron */
    'I', C_ACUTE, (CHAR) 0xCD,          /* I acute */
    C_ACUTE, 'I', (CHAR) 0xCD,          /* I acute */
    'I', '^', (CHAR) 0xCE,              /* I circumflex */
    '^', 'I', (CHAR) 0xCE,              /* I circumflex */
    C_CARON, 'D', (CHAR) 0xCF,          /* D caron */
    'D', C_CARON, (CHAR) 0xCF,          /* D caron */
    '-', 'D', (CHAR) 0xD0,              /* D stroke */
    'D', '-', (CHAR) 0xD0,              /* D stroke */
    'N', C_ACUTE, (CHAR) 0xD1,          /* N acute */
    C_ACUTE, 'N', (CHAR) 0xD1,          /* N acute */
    'N', C_CARON, (CHAR) 0xD2,          /* N caron */
    C_CARON, 'N', (CHAR) 0xD2,          /* N caron */
    'O', C_ACUTE, (CHAR) 0xD3,          /* O acute */
    C_ACUTE, 'O', (CHAR) 0xD3,          /* O acute */
    'O', '^', (CHAR) 0xD4,              /* O circumflex */
    '^', 'O', (CHAR) 0xD4,              /* O circumflex */
    'O', C_DACUTE, (CHAR) 0xD5,         /* O double acute */
    C_DACUTE, 'O', (CHAR) 0xD5,         /* O double acute */
    'O', '"', (CHAR) 0xD6,              /* O diaeresis */
    '"', 'O', (CHAR) 0xD6,              /* O diaeresis */
    'x', 'x', (CHAR) 0xD7,              /* Multiplication sign */
    'X', 'X', (CHAR) 0xD7,              /* Multiplication sign */
    'R', C_CARON, (CHAR) 0xD8,          /* R caron */
    C_CARON, 'R', (CHAR) 0xD8,          /* R caron */
    'U', C_RING, (CHAR) 0xD9,           /* U ring */
    C_RING, 'U', (CHAR) 0xD9,           /* U ring */
    'U', C_ACUTE, (CHAR) 0xDA,          /* U acute */
    C_ACUTE, 'U', (CHAR) 0xDA,          /* U acute */
    'U', C_DACUTE, (CHAR) 0xDB,         /* U double acute */
    C_DACUTE, 'U', (CHAR) 0xDB,         /* U double acute */
    'U', '"', (CHAR) 0xDC,              /* U diaeresis */
    '"', 'U', (CHAR) 0xDC,              /* U diaeresis */
    'Y', C_ACUTE, (CHAR) 0xDD,          /* Y acute */
    C_ACUTE, 'Y', (CHAR) 0xDD,          /* Y acute */
    'T', ',', (CHAR) 0xDE,              /* T cedilla */
    ',', 'T', (CHAR) 0xDE,              /* T cedilla */
    's', 's', (CHAR) 0xDF,              /* German sharp s */
    'r', C_ACUTE, (CHAR) 0xE0,          /* r acute */
    C_ACUTE, 'r', (CHAR) 0xE0,          /* r acute */
    'a', C_ACUTE, (CHAR) 0xE1,          /* a acute */
    C_ACUTE, 'a', (CHAR) 0xE1,          /* a acute */
    'a', '^', (CHAR) 0xE1,              /* a circumflex */
    '^', 'a', (CHAR) 0xE1,              /* a circumflex */
    'a', C_BREVE, (CHAR) 0xE3,          /* a breve */
    C_BREVE, 'a', (CHAR) 0xE3,          /* a breve */
    'a', '"', (CHAR) 0xE4,              /* a diaeresis */
    '"', 'a', (CHAR) 0xE4,              /* a diaeresis */
    'l', C_ACUTE, (CHAR) 0xE5,          /* l acute */
    C_ACUTE, 'l', (CHAR) 0xE5,          /* l acute */
    'c', C_ACUTE, (CHAR) 0xE6,          /* c acute */
    C_ACUTE, 'c', (CHAR) 0xE6,          /* c acute */
    'c', ',', (CHAR) 0xE7,              /* c cedilla */
    ',', 'c', (CHAR) 0xE7,              /* c cedilla */
    'c', C_CARON, (CHAR) 0xE8,          /* c caron */
    C_CARON, 'c', (CHAR) 0xE8,          /* c caron */
    'e', C_ACUTE, (CHAR) 0xE9,          /* e acute */
    C_ACUTE, 'e', (CHAR) 0xE9,          /* e acute */
    'e', C_OGONEK, (CHAR) 0xEA,         /* e ogonek */
    C_OGONEK, 'e', (CHAR) 0xEA,         /* e ogonek */
    'e', '"', (CHAR) 0xEB,              /* e diaeresis */
    '"', 'e', (CHAR) 0xEB,              /* e diaeresis */
    'e', C_CARON, (CHAR) 0xEC,          /* e caron */
    C_CARON, 'e', (CHAR) 0xEC,          /* e caron */
    'i', C_ACUTE, (CHAR) 0xED,          /* i acute */
    C_ACUTE, 'i', (CHAR) 0xED,          /* i acute */
    'i', '^', (CHAR) 0xEE,              /* i circumflex */
    '^', 'i', (CHAR) 0xEE,              /* i circumflex */
    'd', C_CARON, (CHAR) 0xEF,          /* d caron */
    C_CARON, 'd', (CHAR) 0xEF,          /* d caron */
    '-', 'd', (CHAR) 0xF0,              /* d stroke */
    'd', '-', (CHAR) 0xF0,              /* d stroke */
    'n', C_ACUTE, (CHAR) 0xF1,          /* n acute */
    C_ACUTE, 'n', (CHAR) 0xF1,          /* n acute */
    'n', C_CARON, (CHAR) 0xF2,          /* n caron */
    C_CARON, 'n', (CHAR) 0xF2,          /* n caron */
    'o', C_ACUTE, (CHAR) 0xF3,          /* o acute */
    C_ACUTE, 'o', (CHAR) 0xF3,          /* o acute */
    'o', '^', (CHAR) 0xF4,              /* o circumflex */
    '^', 'o', (CHAR) 0xF4,              /* o circumflex */
    'o', C_DACUTE, (CHAR) 0xF5,         /* o double acute */
    C_DACUTE, 'o', (CHAR) 0xF5,         /* o double acute */
    'o', '"', (CHAR) 0xF6,              /* o diaeresis */
    '"', 'o', (CHAR) 0xF6,              /* o diaeresis */
    '-', ':', (CHAR) 0xF7,              /* Division sign */
    'r', C_CARON, (CHAR) 0xF8,          /* r caron */
    C_CARON, 'r', (CHAR) 0xF8,          /* r caron */
    'u', C_RING, (CHAR) 0xF9,           /* u ring */
    C_RING, 'u', (CHAR) 0xF9,           /* u ring */
    'u', C_ACUTE, (CHAR) 0xFA,          /* u acute */
    C_ACUTE, 'u', (CHAR) 0xFA,          /* u acute */
    'u', C_DACUTE, (CHAR) 0xFB,         /* u double acute */
    C_DACUTE, 'u', (CHAR) 0xFB,         /* u double acute */
    'u', '"', (CHAR) 0xFC,              /* u diaeresis */
    '"', 'u', (CHAR) 0xFC,              /* u diaeresis */
    'y', C_ACUTE, (CHAR) 0xFD,          /* y acute */
    C_ACUTE, 'y', (CHAR) 0xFD,          /* y acute */
    't', ',', (CHAR) 0xFE,              /* t cedilla */
    ',', 't', (CHAR) 0xFE,              /* t cedilla */
    C_DOT, C_DOT, (CHAR) 0xFF,          /* Dot above */
    /*
    The following group is for entering ASCII characters that are otherwise
    impossible to enter, e.g. because they are dead-key combinations.
    */
    '+', '+', '#',                      /* Number sign */
    'A', 'A', '@',                      /* At sign */
    'a', 'a', '@',                      /* At sign */
    '(', '(', '[',                      /* Left bracket */
    '/', '/', '\\',                     /* Backslash */
    '/', '<', '\\',                     /* Backslash */
    ')', ')', ']',                      /* Right bracket */
    '(', '-', '{',                      /* Left brace */
    '/', '^', '|',                      /* Vertical bar */
    ')', '-', '}',                      /* Right brace */
    (CHAR)0x27, '.', C_ACUTE,           /* Apostrophe */
    '.', (CHAR)0x27, C_ACUTE,           /* Apostrophe */
    '^', '^', '^',                      /* Circumflex or caret */
    '`', '`', '`',                      /* Grave accent or backquote */
    '~', '~', '~',                      /* Tilde */
    ',', '.', ',',                      /* Comma */
    '.', ',', ',',                      /* Comma */
    '"', '"', '"',                      /* Doublequote */
    ':', ':', (CHAR) 0xA8               /* Diaeresis */
};
int nl2ktab = (sizeof(l2ktab) / sizeof(struct compose_key_tab));

extern vik_rec vik;
#endif /* NOKVERBS */

#if defined(_MSC_VER) && _MSC_VER >= 1920
/* The round function is new in Visual C++ 2013. */
#define K95ROUND(x) ((int)round((x)))
#else
/* It is absent in Open Watcom 1.9 and I'm not sure about the various MinGW/GCC
 * versions so for now they get the fallback option */
#define K95ROUND(x) ((int)ckround((x), 0, NULL, 0))
#endif

/* A few colour table entries below 16 are swapped around compared
 * to the standard xterm color table for OS/2 reasons. This is equivalent
 * to sgrcols, but valid for the full 0-15 range (sgrcols only covers 0-7) */
int color_index_to_vio(int index) {
	if (index > 15) return index;
	switch(index) {
        case 1: return 4; break;
        case 3: return 6; break;
        case 4: return 1; break;
        case 6: return 3; break;
        case 9: return 12; break;
        case 11: return 14; break;
        case 12: return 9; break;
        case 14: return 11; break;
        default: break;
    }
    return index;
}

int color_index_from_vio(int index) {
	if (index > 15) return index;
	switch(index) {
        case 4: return 1; break;
        case 6: return 3; break;
        case 1: return 4; break;
        case 3: return 6; break;
        case 12: return 9; break;
        case 14: return 11; break;
        case 9: return 12; break;
        case 11: return 14; break;
        default: break;
    }
    return index;
}

unsigned char palette_max_index(int palette_id) {
    switch(palette_id) {
        case CK_PALETTE_XT88:
        case CK_PALETTE_XTRGB88:
            return 87;
#ifdef CK_PALETTE_WY370
        case CK_PALETTE_WY370:
            return 65;
#endif /* CK_PALETTE_WY370 */
        case CK_PALETTE_XT256:
        case CK_PALETTE_XTRGB:
            return 255;
    }
    return 15;
}

unsigned char current_palette_max_index() {
    return palette_max_index(colorpalette);
}

ULONG* palette_rgb_table(int palette_id) {
    switch(palette_id) {
        case CK_PALETTE_XT88:
        case CK_PALETTE_XTRGB88:
            return RGBTable88;
#ifdef CK_PALETTE_WY370
        case CK_PALETTE_WY370:
            return WY370RGBTable;
#endif /* CK_PALETTE_WY370 */
        case CK_PALETTE_XT256:
        case CK_PALETTE_XTRGB:
            return RGBTable256;
        case CK_PALETTE_VT525:
            return VT525RGBTable;
        case CK_PALETTE_VT525_M:
            return VT525MonoRGBTable;
        case CK_PALETTE_VT525_A:
            return VT525ATCRGBTable;
    }
    return RGBTable;
}

ULONG* current_palette_rgb_table() {
    return palette_rgb_table(colorpalette);
}

ULONG* palette_saved_rgb_table(int palette_id) {
    switch(palette_id) {
        case CK_PALETTE_XT88:
        case CK_PALETTE_XTRGB88:
            return SavedRGBTable88;
#ifdef CK_PALETTE_WY370
        case CK_PALETTE_WY370:
            return SavedWY370RGBTable;
#endif /* CK_PALETTE_WY370 */
        case CK_PALETTE_XT256:
        case CK_PALETTE_XTRGB:
            return SavedRGBTable256;
        case CK_PALETTE_VT525:
            return SavedVT525RGBTable;
        case CK_PALETTE_VT525_M:
            return SavedVT525MonoRGBTable;
        case CK_PALETTE_VT525_A:
            return SavedVT525ATCRGBTable;
    }
    return SavedRGBTable;
}

ULONG* current_palette_saved_rgb_table() {
    return palette_saved_rgb_table(colorpalette);
}

void reset_palette(int palette_id) {
    int palmax, i;
    ULONG *saved;
    ULONG *current;

    palmax = current_palette_max_index();
    saved = palette_saved_rgb_table(palette_id);
    current = palette_rgb_table(palette_id);

    for (i = 0; i <= palmax; i++) {
        current[i] = saved[i];
    }
}

void reset_palettes() {
    int i;
    for (i = 0; i < 256; i++) RGBTable256[i] = SavedRGBTable256[i];
    for (i = 0; i < 88; i++) RGBTable88[i] = SavedRGBTable88[i];
    for (i = 0; i < 16; i++) {
        RGBTable[i] = SavedRGBTable[i];
        VT525RGBTable[i] = SavedVT525RGBTable[i];
        VT525MonoRGBTable[i] = SavedVT525MonoRGBTable[i];
        VT525ATCRGBTable[i] = SavedVT525ATCRGBTable[i];
    }
#ifdef CK_PALETTE_WY370
    for (i = 0; i < 65; i++) WY370RGBTable[i] = SavedWY370RGBTable[i];
#endif /* CK_PALETTE_WY370 */
}

void reset_decatc_assignments() {
    /* TODO: These should probably be customisable by the user somehow */
    decatc_colors[0] = cell_video_attr_set_colors(2,0);
    decatc_colors[1] = cell_video_attr_set_colors(1,0);
    decatc_colors[2] = cell_video_attr_set_colors(6,4);
    decatc_colors[3] = cell_video_attr_set_colors(6,0);
    decatc_colors[4] = cell_video_attr_set_colors(3,0);
    decatc_colors[5] = cell_video_attr_set_colors(1,4);
    decatc_colors[6] = cell_video_attr_set_colors(7,0);
    decatc_colors[7] = cell_video_attr_set_colors(1,0);
    decatc_colors[8] = cell_video_attr_set_colors(6,4);
    decatc_colors[9] = cell_video_attr_set_colors(3,4);
    decatc_colors[10] = cell_video_attr_set_colors(7,0);
    decatc_colors[11] = cell_video_attr_set_colors(7,4);
    decatc_colors[12] = cell_video_attr_set_colors(5,4);
    decatc_colors[13] = cell_video_attr_set_colors(5,0);
    decatc_colors[14] = cell_video_attr_set_colors(7,4);
    decatc_colors[15] = cell_video_attr_set_colors(5,4);
}

/** Finds the nearest color in the current palette to the supplied RGB values
 * (colour quantization). Allows higher color depths to be mapped on to smaller
 * palettes. In 16-color builds, this always maps on to the aixterm-16 palette
 * regardless of the currently chosen palette.
 */
int nearest_palette_color_rgb(int palette_id, unsigned char r, unsigned char g, unsigned char b) {
    ULONG *palette = NULL;
    int palette_max = 15;
    int min = 0xfffffff;
    int result = 0;
    int i;

    /* Figure out which palette we're using. In 16-color builds, there are only
     * 4-bits per color in cell_video_attr_t, so we always convert to the
     * 16-color palette. The other palettes only exist in such builds as a
     * source of RGB values to convert *from*. Use the Saved version of the
     * 16-color palette in case the host has customised it. */
#ifdef CK_COLORS_16
    palette = SavedRGBTable;
    palette_max = 15;
#else /* CK_COLORS_16 */
    palette_max = palette_max_index(palette_id);
    palette = palette_rgb_table(palette_id);
#endif /* CK_COLORS_16 */

	for (i = 0; i < palette_max; i++) {
    	int r_diff, g_diff, b_diff, diff;
        b_diff = b - ((palette[i] & 0x00FF0000)>>16);
		g_diff = g - ((palette[i] & 0x0000FF00)>>8);
    	r_diff = r - ((palette[i] & 0x000000FF));

        diff = r_diff*r_diff + g_diff*g_diff + b_diff*b_diff;
        if (diff < min) {
        	min = diff;
            result = i;
        }
    }

    return result;
}


/* Looks up the color in the specified color palette, then converts that to
 * a color in the current color palette */
int nearest_palette_color_palette(int palette_id, int palette_index) {
    unsigned char r, g, b, palette_max;
    ULONG *palette;

    /* Figure out which palette we're using */
    palette = palette_rgb_table(palette_id);
    palette_max = palette_max_index(palette_id);

	if (palette_index > palette_max) return -1;

	b = (palette[palette_index] & 0x00FF0000)>>16;
	g = (palette[palette_index] & 0x0000FF00)>>8;
    r = (palette[palette_index] & 0x000000FF);

    return nearest_palette_color_rgb(colorpalette, r, g, b);
}

/* Converts a color attribute in the specified palette to a color attribute
 * in the current palette. */
cell_video_attr_t cell_video_attr_to_palette(int source_palette_id,
        cell_video_attr_t attr) {
    int src_fg_idx, src_bg_idx;
    int fg_idx, bg_idx;
    src_fg_idx = cell_video_attr_foreground(attr);
    src_bg_idx = cell_video_attr_background(attr);

    fg_idx = nearest_palette_color_palette(
        source_palette_id, src_fg_idx);
    bg_idx = nearest_palette_color_palette(
        source_palette_id, src_bg_idx);

    if (fg_idx >= 0 && bg_idx >= 0) {
        return cell_video_attr_set_colors(fg_idx, bg_idx);
    } else { /* should never happen */
        return cell_video_attr_set_colors(8,0);
    }
}

/* Only required for Visual C++ 2012 and older which don't support compound
 * literals. For 2013 and up, a macro is used. */
#if _MSC_VER < 1800
#ifdef CK_COLORS_24BIT
/* Sets all values in a 24-bit color attribute */
cell_video_attr_t cell_video_attr_set(unsigned char flags,
        unsigned char fg_r, unsigned char fg_g, unsigned char fg_b,
        unsigned char bg_r, unsigned char bg_g, unsigned char bg_b) {
    cell_video_attr_t value = { flags, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b };
    return value;
}
#else
#ifdef CK_COLORS_DEBUG
cell_video_attr_t cell_video_attr_set(unsigned char value) {
    cell_video_attr_t x;
    x.a = value;
    x.b = 0;
    return x;
}
#endif /* CK_COLORS_DEBUG */
#endif /* CK_COLORS_24BIT */
#endif /* _MSC_VER < 1800 */


#ifndef CK_COLORS_DEBUG
ULONG cell_video_attr_foreground_rgb(cell_video_attr_t attr) {
    ULONG *pal;
    int palmax, idx;

#ifdef CK_COLORS_24BIT
    if (!cell_video_attr_fg_is_indexed(attr)) {
        return cell_video_attr_fg_to_rgb(attr);
    }
#endif /* CK_COLORS_24BIT */

    pal = current_palette_rgb_table();
    palmax = current_palette_max_index() + 1;
    idx = cell_video_attr_foreground(attr);

    return pal[idx % palmax];
}

ULONG cell_video_attr_background_rgb(cell_video_attr_t attr) {
    ULONG *pal;
    int palmax, idx;

#ifdef CK_COLORS_24BIT
    if (!cell_video_attr_bg_is_indexed(attr)) {
        return cell_video_attr_bg_to_rgb(attr);
    }
#endif /* CK_COLORS_24BIT */

    pal = current_palette_rgb_table();
    palmax = current_palette_max_index() + 1;
    idx = cell_video_attr_background(attr);

    return pal[idx % palmax];
}
#endif /* CK_COLORS_DEBUG */

/* Converts the supplied R/G/B values (0-255) to the DEC H/L/S coordinate
 * system which places Red at zero degrees rather than blue. Result is returned
 * via the h, l and s parameters. The method for doing this is documented in
 * AA-MI676A-TE "A Guide to migrating VWS Applications to DECwindows",
 * September 1989, Appendix F */
void rgb_to_hls(unsigned char r, unsigned char g, unsigned char b,
                float *h, float *l, float *s) {
    float red, green, blue, max_value, min_value;

    red = r / 255.0;
    green = g / 255.0;
    blue = b / 255.0;

    max_value = ((red > green) ? red:green) > blue ?
                ((red > green) ? red:green) : blue;
    min_value = ((red < green) ? red:green) < blue ?
                ((red < green) ? red:green) : blue;

    /* Lightness */
    *l = (max_value + min_value) / 2;

    if (max_value == min_value) {
        *s = 0;
        *h = -1;
    } else {
        float red_content, green_content, blue_content;
        float color_span = max_value - min_value;

        /* Saturation */
        if (*l < 0.5) {
            *s = color_span / (max_value + min_value);
        } else {
            *s = color_span / (2.0 - max_value - min_value);
        }

        /* Hue */
        red_content = (max_value - red) / color_span;
        green_content = (max_value - green) / color_span;
        blue_content = (max_value - blue) / color_span;

        if (red == max_value) {
            *h = blue_content - green_content;
        } else {
            if (green == max_value) {
                *h = 2.0 + red_content - blue_content;
            } else {
                *h = 4.0 + green_content - red_content;
            }
        }

        *h = *h * 60.0;

        /* Make sure hue is positive */
        while (*h < 0.0) {
            *h += 360.0;
        }
    }

    /* Put blue at zero degrees */
    *h = *h + 120;

    while (*h >= 360.0) {
        *h -= 360.0;
    }

    /* Convert lightness and saturation to percentages */
    *l = *l * 100;
    *s = *s * 100;
}

#define ONE_THIRD (1.0/3.0)
#define ONE_SIXTH (1.0/6.0)
#define TWO_THIRD (2.0/3.0)

float
hls_v(float m1, float m2, float hue) {
    float temp = fmod(hue, 1.0);
    if (hue < 0) {
        hue = hue - temp;
    } else {
        hue = temp;
    }
    if (hue < ONE_SIXTH) {
        return m1 + (m2 - m1) * hue * 6.0;
    } else if (hue < 0.5) {
        return m2;
    } else if (hue < TWO_THIRD) {
        return m1 + (m2 - m1) * (TWO_THIRD - hue) * 6.0;
    }
    return m1;
}

void
hls_to_rgb(int h, int l, int s,
           int* r, int* g, int* b)
{
    float hue, lightness, saturation, m1, m2;
    hue = h / 360.0;
    lightness = l / 100.0;
    saturation = s / 100.0;

    if (saturation == 0.0) {
        int x = K95ROUND(lightness * 255);
        *r = *g = *b = x;
        return;
    }

    if (lightness <= 0.5) {
        m2 = lightness * (1.0 + saturation);
    } else {
        m2 = lightness + saturation - (lightness * saturation);
    }
    m1 = 2.0 * lightness - m2;

    *r = K95ROUND(hls_v(m1, m2, hue) * 255);
    *g = K95ROUND(hls_v(m1, m2, hue - ONE_THIRD) * 255);
    *b = K95ROUND(hls_v(m1, m2, hue + ONE_THIRD) * 255);
}


#undef ONE_THIRD
#undef ONE_SIXTH
#undef TWO_THIRD

USHORT
xldecgrph( CHAR c ) {
#ifdef COMMENT
    if ( ck_isunicode() ) {
        return(c);
    }
    else {
        static unsigned char graphicset[32] = { /* VT100/200 graphic characters */
            0x20,
            0x04, 0xB0, 0x1A, 0x17, 0x1B, 0x19, 0xF8, 0xF1,
            0x15, 0x12, 0xD9, 0xBF, 0xDA, 0xC0, 0xC5, 0xC4,
            0xC4, 0xC4, 0xC4, 0xC4, 0xC3, 0xB4, 0xC1, 0xC2,
            0xB3, 0xF3, 0xF2, 0xE3, 0x9D, 0x9C, 0xFA
        };
        return graphicset[c>127 ? c-222 : c-95] ;
    }
#else /* COMMENT */
    USHORT cx = 0;
    if ( ck_isunicode() ) {
        cx = (*xl_u[TX_DECSPEC])(c);
        if ( win95hsl && cx >= 0x23BA && cx <= 0x23BD )
            cx = tx_hslsub(cx);
        else if ( cx >= 0xE000 && cx <= 0xF8FF )
            cx = tx_usub(cx);
        if (win95lucida && cx > 0x017f)
            cx = tx_lucidasub(cx);
    }
    else {
        cx = (*xl_u[TX_DECSPEC])(c);
        if ( GNOW->itol )
            cx = (*GNOW->itol)(cx);
    }
    return(cx);
#endif /* COMMENT */
}

USHORT
xldectech( CHAR c ) {
    USHORT cx = 0;
    if ( ck_isunicode() ) {
        cx = (*xl_u[TX_DECTECH])(c);
        if ( win95hsl && cx >= 0x23BA && cx <= 0x23BD )
            cx = tx_hslsub(cx);
        else if ( cx >= 0xE000 && cx <= 0xF8FF )
            cx = tx_usub(cx);
        if (win95lucida && cx > 0x017f)
            cx = tx_lucidasub(cx);
    }
    else {
#ifdef COMMENT
    static unsigned char graphicset[94] = { /* VT200 technical characters */
             '?', '?', '?', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', ' ', ' ', ' ', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', '?', ' ', '?', ' ', ' ', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?', '?',
        '?', '?', '?', '?', '?', '?', '?'
    };
        cx = graphicset[c>127 ? c-160 : c-33] ;
#else /* COMMENT */
        cx = (*xl_u[TX_DECTECH])(c);
        if ( GNOW->itol )
            cx = (*GNOW->itol)(cx);
#endif /* COMMENT */
    }
    return(cx);
}

USHORT
xlh19grph( CHAR c ) {
    USHORT cx=0;
    if ( ck_isunicode() ) {
        cx = (*xl_u[TX_H19GRAPH])(c);
        if ( win95hsl && cx >= 0x23BA && cx <= 0x23BD )
            cx = tx_hslsub(cx);
        else if ( cx >= 0xE000 && cx <= 0xF8FF )
            cx = tx_usub(cx);
        if (win95lucida && cx > 0x017f)
            cx = tx_lucidasub(cx);
    }
    else {
#ifdef COMMENT
    static unsigned char graphicset[33] = { /* Heath-19 graphic characters */
        0xFA, 0xDD, 0x5C/*0xB3*/, 0xC4, 0xC5,
        0xBF, 0xD9, 0xC0, 0xDA, 0xF1,
        0x1A, 0xDB, 0xFE, 0x19, 0xDC,
        0xDC, 0xDF, 0xDF, 0xDF, 0xDE,
        0x2F/*0xDE*/, 0xC2, 0xB4, 0xC1, 0xC3,
        0x58, 0x2F, 0x5C, 0x16, 0x5F,
        0xB3, 0xB3, 0X14
    };
        cx =  graphicset[c>127 ? c-211 : c-94] ;
#else
        cx = (*xl_u[TX_H19GRAPH])(c);
        if ( GNOW->itol )
            cx = (*GNOW->itol)(cx);
#endif /* COMMENT */
    }
    return(cx);
}

#ifdef CKLEARN
ULONG learnt1;
char learnbuf[LEARNBUFSIZ] = { NUL, NUL };
int  learnbc = 0;
int  learnbp = 0;
int  learnst = 0;

VOID
learnreset()
{
    learnbuf[0] = NUL;
    learnbc = 0;
    learnbp = 0;
    learnst = 0;
}

VOID
learnnet(int c)
{
    if (learning && learnst != LEARN_KEYBOARD) {
        learnbuf[learnbp++] = c;
        if ( learnbp >= LEARNBUFSIZ )
            learnbp = 0;
        learnbc++;
        learnst = LEARN_NET;
    }
}

VOID
learnkeyb(con_event evt, int state) {   /* Learned script keyboard character */
    char buf[64];
    char * ptr=NULL;
    int cc;

    if (!learning || !learnfp)
      return;

    switch (evt.type) {
    case key:
        cc = evt.key.scancode;
        if (cc == 0) {
            ptr = "\\N";
        } else if (cc < SP || cc > 126 && cc < 160) {
            ckmakmsg(buf,64,"\\{",ckitoa((int)cc),"}",NULL);
            ptr = buf;
        } else {
            buf[0] = evt.key.scancode ;
            buf[1] = '\0';
            ptr = buf;
        }
        break;

#ifndef NOKVERBS
    case kverb: {
        extern struct keytab kverbs[];
        extern int nkverbs;
        int i;

        for ( i=0; i<nkverbs; i++ ) {
            if ( kverbs[i].kwval == evt.kverb.id ) {
                ckmakmsg(buf,64,"\\K{",kverbs[i].kwd,"}",NULL);
                ptr = buf;
            }
        }
        break;
    }
#endif /* NOKVERBS */
    case macro:
        ptr = evt.macro.string;
        break;

    case literal:
        ptr = evt.literal.string;
        break;

    case esc:
        buf[0] = ESC;
        buf[1] = evt.esc.key & ~F_ESC ;
        buf[2] = '\0' ;
        ptr = buf;
        break;

    case csi:
        buf[0] = ESC;
        buf[1] = '[' ;
        buf[2] = evt.csi.key & ~F_CSI ;
        buf[3] = '\0' ;
        ptr = buf;
        break;
    }

    switch (learnst) {                  /* Learn state... */
      case LEARN_NEUTRAL:
      case LEARN_NET:
        if (learnbc > 0) {              /* Have net characters? */
            char nbuf[LEARNBUFSIZ];
            int i, j, n;
            ULONG t;

            t = (ULONG) time(0);        /* Calculate INPUT timeout */
            j = t - learnt1;
            j += (j / 4) > 0 ? (j / 4) : 1; /* Add some slop */
            if (j < 2) j = 2;               /* 2 seconds minimum */

            fputs("\r\nINPUT ",learnfp);/* Give INPUT command for them */
            fputs(ckitoa(j),learnfp);
            fputs(" {",learnfp);
            learnt1 = t;

            n = LEARNBUFSIZ;
            if (learnbc < LEARNBUFSIZ) {  /* Circular buffer */
                n = learnbc;              /*  hasn't wrapped yet. */
                learnbp = 0;
            }
            j = 0;                      /* Copy to linear buffer */
            for (i = 0; i < n; i++) {   /* Number of chars in circular buf */

                cc = learnbuf[(learnbp + i) % LEARNBUFSIZ];

                /* Later account for prompts that end with a newline? */

                if (cc == CK_CR && j > 0) {
                    if (nbuf[j-1] != LF)
                      j = 0;
                }
                nbuf[j++] = cc;
            }
            for (i = 0; i < j; i++) {   /* Now copy out the buffer */
                cc = nbuf[i];           /* interpreting control chars */
                if (cc == 0) {          /* We don't INPUT NULs */
                    continue;
                } else if (cc < SP ||   /* Controls need quoting */
                           cc > 126 && cc < 160) {
                    ckmakmsg(buf,64,"\\{",ckitoa((int)cc),"}",NULL);
                    fputs(buf,learnfp);
                } else {                /* Plain character */
                    putc(cc,learnfp);
                }
            }
            fputs("}\nIF FAIL STOP 1 INPUT timeout",learnfp);
            learnbc = 0;
        }
        learnbp = 0;
        fputs("\nPAUSE 1\nOUTPUT ",learnfp); /* Emit OUTPUT and fall thru */

      case LEARN_KEYBOARD:
        if ( ptr )
            fputs(ptr,learnfp);
    }
    learnst = state;
}
#endif /* CKLEARN */
#endif /* NOLOCAL */

/* ------------------------------------------------------------------ */
/* Printer functions                                                  */
/* ------------------------------------------------------------------ */

/* Text2PS */

/*
  Postscript Prolog, to be inserted at the beginning of the output file.
  The %% Comments are to make the file conformant with Adobe's "Postscript
  File Structuring Conventions", which allow page-oriented operations in
  Postscript previewers, page pickers, etc.
*/
char *psprolog[] = {                      /* Standard prolog */
    "%!PS-Adobe-1.0",                   /* Works with Postscript 1.0 */
    "%%Title: oofa",
    "%%DocumentFonts: Courier CourierLatin1",
    "%%Creator: K95",
    "%%Pages: (atend)",
    "%%EndComments",
/*
  Postscript font reencoding.  The standard encoding does not have the
  characters needed for Latin-1.

  Unfortunately, the font reencoding methods listed in the Postscript
  Cookbook simply do not work with the Apple Laserwriter (even though they
  did work with other Postscript devices).  The method described in the
  Adobe PostScript Language Reference Manual (2nd Ed) to change from the
  StandardEncoding vector to the ISOLatin1Encoding vector works only with
  the LaserWriter-II, but not older LaserWriters.

  This method, suggested by Bur Davis at Adobe, works around the fact that
  Courier was a "stroke font" in pre-version-47.0 Postscript, in which many of
  the accented characters are composed from other characters (e.g. i-grave =
  dotless i + grave).  It is probably not the most efficient possible solution
  (an iterative method might be better), but it works.
*/
    "/CourierLatin1 /Courier findfont dup dup maxlength dict begin",
    "{",
    "    1 index /FID ne { def } { pop pop } ifelse",
    "} forall",
    "/Encoding exch 1 index get 256 array copy def",
/*
  The following characters are added at the C1 positions 128-153, for printing
  non-Latin1 character sets such as IBM code pages, DEC MCS, NeXT, etc.  Note
  that we cannot use characters from the Symbol font.  Characters from
  different fonts cannot be mixed.  Anyway, the Symbol font is not fixed-width.
*/
    "Encoding 128 /quotesingle put",
    "Encoding 129 /quotedblleft put",
    "Encoding 131 /fi put",
    "Encoding 132 /endash put",
    "Encoding 133 /dagger put",
    "Encoding 134 /periodcentered put",
    "Encoding 135 /bullet put",
    "Encoding 136 /quotesinglbase put",
    "Encoding 137 /quotedblbase put",
    "Encoding 138 /quotedblright put",
    "Encoding 139 /ellipsis put",
    "Encoding 140 /perthousand put",
    "Encoding 141 /dotaccent put",
    "Encoding 142 /hungarumlaut put",
    "Encoding 143 /ogonek put",
    "Encoding 144 /caron put",
    "Encoding 145 /fl put",
    "Encoding 146 /emdash put",
    "Encoding 147 /Lslash put",
    "Encoding 148 /OE put",
    "Encoding 149 /lslash put",
    "Encoding 150 /oe put",
    "Encoding 151 /florin put",
    "Encoding 152 /fraction put",
    "Encoding 153 /daggerdbl put",
/*
  The following six characters are required for pre-47.0 PostScript versions,
  which compose accented Courier characters by putting together the base
  character and the accent.
*/
    "Encoding 154 /dotlessi put",
    "Encoding 155 /grave put",
    "Encoding 156 /circumflex put",
    "Encoding 157 /tilde put",
    "Encoding 158 /breve put",
    "Encoding 159 /ring put",
/*
  The remainder follow the normal ISO 8859-1 encoding.
*/
    "Encoding 160 /space put",
    "Encoding 161 /exclamdown put",
    "Encoding 162 /cent put",
    "Encoding 163 /sterling put",
    "Encoding 164 /currency put",
    "Encoding 165 /yen put",
    "Encoding 166 /brokenbar put",
    "Encoding 167 /section put",
    "Encoding 168 /dieresis put",
    "Encoding 169 /copyright put",
    "Encoding 170 /ordfeminine put",
    "Encoding 171 /guillemotleft put",
    "Encoding 172 /logicalnot put",
    "Encoding 173 /hyphen put",
    "Encoding 174 /registered put",
    "Encoding 175 /macron put",
    "Encoding 176 /degree put",
    "Encoding 177 /plusminus put",
    "Encoding 178 /twosuperior put",
    "Encoding 179 /threesuperior put",
    "Encoding 180 /acute put",
    "Encoding 181 /mu put",
    "Encoding 182 /paragraph put",
    "Encoding 183 /bullet put",
    "Encoding 184 /cedilla put",
    "Encoding 185 /onesuperior put",
    "Encoding 186 /ordmasculine put",
    "Encoding 187 /guillemotright put",
    "Encoding 188 /onequarter put",
    "Encoding 189 /onehalf put",
    "Encoding 190 /threequarters put",
    "Encoding 191 /questiondown put",
    "Encoding 192 /Agrave put",
    "Encoding 193 /Aacute put",
    "Encoding 194 /Acircumflex put",
    "Encoding 195 /Atilde put",
    "Encoding 196 /Adieresis put",
    "Encoding 197 /Aring put",
    "Encoding 198 /AE put",
    "Encoding 199 /Ccedilla put",
    "Encoding 200 /Egrave put",
    "Encoding 201 /Eacute put",
    "Encoding 202 /Ecircumflex put",
    "Encoding 203 /Edieresis put",
    "Encoding 204 /Igrave put",
    "Encoding 205 /Iacute put",
    "Encoding 206 /Icircumflex put",
    "Encoding 207 /Idieresis put",
    "Encoding 208 /Eth put",
    "Encoding 209 /Ntilde put",
    "Encoding 210 /Ograve put",
    "Encoding 211 /Oacute put",
    "Encoding 212 /Ocircumflex put",
    "Encoding 213 /Otilde put",
    "Encoding 214 /Odieresis put",
    "Encoding 215 /multiply put",
    "Encoding 216 /Oslash put",
    "Encoding 217 /Ugrave put",
    "Encoding 218 /Uacute put",
    "Encoding 219 /Ucircumflex put",
    "Encoding 220 /Udieresis put",
    "Encoding 221 /Yacute put",
    "Encoding 222 /Thorn put",
    "Encoding 223 /germandbls put",
    "Encoding 224 /agrave put",
    "Encoding 225 /aacute put",
    "Encoding 226 /acircumflex put",
    "Encoding 227 /atilde put",
    "Encoding 228 /adieresis put",
    "Encoding 229 /aring put",
    "Encoding 230 /ae put",
    "Encoding 231 /ccedilla put",
    "Encoding 232 /egrave put",
    "Encoding 233 /eacute put",
    "Encoding 234 /ecircumflex put",
    "Encoding 235 /edieresis put",
    "Encoding 236 /igrave put",
    "Encoding 237 /iacute put",
    "Encoding 238 /icircumflex put",
    "Encoding 239 /idieresis put",
    "Encoding 240 /eth put",
    "Encoding 241 /ntilde put",
    "Encoding 242 /ograve put",
    "Encoding 243 /oacute put",
    "Encoding 244 /ocircumflex put",
    "Encoding 245 /otilde put",
    "Encoding 246 /odieresis put",
    "Encoding 247 /divide put",
    "Encoding 248 /oslash put",
    "Encoding 249 /ugrave put",
    "Encoding 250 /uacute put",
    "Encoding 251 /ucircumflex put",
    "Encoding 252 /udieresis put",
    "Encoding 253 /yacute put",
    "Encoding 254 /thorn put",
    "Encoding 255 /ydieresis put",
    "currentdict end definefont",
/*
  Set the font and define functions for adding lines and printing pages.
*/
    "/CourierLatin1 findfont 11 scalefont setfont",
    "/StartPage{/sv save def 48 765 moveto}def",
    "/ld -11.4 def",                    /* Line spacing */
    "/yline 765 def",                   /* Position of top line */
    "/U{show",                          /* Show line, don't advance */
    "  48 yline moveto}def",
    "/S{show",                          /* Show line, move to next line */
    "  /yline yline ld add def",
    "  48 yline moveto}def",
    "/L{ld mul yline add /yline exch def", /* Move down n lines  */
    "  48 yline moveto}def",
    "/EndPage{showpage sv restore}def",
    "%%EndProlog",                      /* End of prolog. */
    "%%Page: 1 1",                      /* Number the first page. */
    "StartPage",                        /* And start it. */
    ""                                  /* Empty string = end of array. */
};                                      /* End PS Prolog */

#define NOESCSEQ        /* We don't support this, should be no need. */
#ifndef NOESCSEQ        /* Swallow ANSI escape and control sequences */
#define ESCSEQ          /* unless -DNOESCSEQ given on cc command line. */
#endif /* NOESCSEQ */

#define PS_WIDTH 80     /* Portrait printer line width, characters */
#define PS_LENGTH 66    /* Portrait printer page length, lines */
#define MAXPSLENGTH 256

/* TextPS Globals */

static int hpos = 0,                    /* Character number in line buffer */
  maxhpos = 0,                          /* Longest line in buffer */
  page = 0,                             /* Page number */
  line = 0,                             /* Line number */
  blank = 0,                            /* Blank line count */
  pagefull = 0,                         /* Flag for page overflow */
  psflag = 0,                           /* Flag for file already postscript */
  proflg = 0,                           /* Prolog done */
  shift = 0,                            /* Shift state */
  ps_escape = 0;

int ps_width = PS_WIDTH;                /* Paper width, characters */
int ps_length = PS_LENGTH;              /* Paper length, characters */

int txt2ps = 0;                         /* Flag set if we convert to PS */

/* Data structures */

/*
  buf is the line buffer.  columns (indexed by hpos) are the characters
  in the line, rows are overstruck lines.  At display time (see addline),
  buf is treated as a 3-dimensional array, with the extra dimension being
  for wraparound.  The total size of the buffer is 80 chars per line times
  66 lines per page times 10 levels of overstriking = 52,800.  This allows
  files that contain absolutely no linefeeds to still print correctly.
*/
#define BUFNUM 10                       /* Number of overstrike buffers */
#define BUFWID 5280                     /* Max characters per line */

unsigned char buf[BUFNUM][BUFWID];      /* Line buffers */
unsigned char outbuf[400];              /* Output buffer */
int linesize[BUFNUM];                   /* Size of each line in buffer */
int bufs[MAXPSLENGTH];                  /* # overstrike buffers per line */

/* Line and page display routines */

/* Forward declarations */

void addline();                         /* Add line to page */
void addchar();                         /* Add character to line */
void newpage();                         /* New page */

void
clearbuf() {                            /* Clear line buffer */
    int i;
/*
  Note: if a loop is used instead of memset, this program runs
  veeeery slooooooowly.
*/
    memset(buf,SP,BUFNUM * BUFWID);     /* Clear buffers and counts */
    for (i = 0; i < BUFNUM; linesize[i++] = -1) ;
    for (i = 0; i < ps_length; bufs[i++] = 0) ;
    hpos = 0;                           /* Reset line buffer pointer */
    maxhpos = 0;                        /* And maximum line ps_length */
}

void
doprolog() {                            /* Output the PostScript prolog */
    int i;
    CHAR crlf[2] = { CK_CR, LF };

    for (i = 0; *psprolog[i]; i++) {
#ifdef NT
        if ( winprint ) {
            int rc;
            rc = Win32PrtWrite( psprolog[i], strlen(psprolog[i]) );
            debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
            rc = Win32PrtWrite( crlf, 2 );
        }
        else
#endif /* NT */
        if ( lst ) {
            int rc;
            rc = fwrite( psprolog[i], 1, strlen(psprolog[i]), lst );
            debug(F111,"txt2ps_char","fwrite rc",rc);
            rc = fwrite( crlf, 1, 2, lst );
        }
        proflg++;
    }
}

void
addchar(c) unsigned char c; {           /* Add character to line buffer */
    int i, m;
#ifdef OS2ONLY
    int * bp;
#endif /* OS2ONLY */

    if (c < SP || c == DEL) c = SP;     /* ASCII controls become spaces. */

    for (i = 0; i < BUFNUM; i++) {      /* Find first */
        if (hpos > linesize[i]) {       /* available overstrike buffer */
            buf[i][hpos] = c;           /* Deposit character */
            linesize[i] = hpos;         /* Remember size of this buffer. */
            m = hpos / ps_width;        /* Line-wrap segment number. */
            if (bufs[m] < i) {          /* Highest overstrike buffer used */
#ifdef OS2ONLY
                bp = &bufs[m];          /*   (os2 compiler bug)           */
                *bp = i;                /*   for this line-wrap segment.  */
#else /* OS2ONLY */
                bufs[m] = i;            /*   for this line-wrap segment   */
#endif /* OS2ONLY */
            }
            break;
        }
    }
    if (hpos > maxhpos) maxhpos = hpos; /* Remember maximum line position. */
    if (++hpos >= BUFWID)               /* Increment line position. */
      addline();                        /* If buffer full, dump it. */
}

void
addline() {                             /* Add a line to the current page */
    int i, j, k, m, n, y, wraps;
    unsigned char *p, *q, c;
    CHAR lf = LF;

    if (line == 0 && page == 1) {       /* First line of file? */
        if (!strncmp(buf[0],"%!",2)) {  /* Already Postscript? */
            psflag++;                   /* Yes, set this flag & just copy */
            buf[0][hpos] = '\0';        /* Trim trailing blanks */
#ifdef NT
            if ( winprint ) {               /* Print this line */
                int rc;
                rc = Win32PrtWrite( buf[0], strlen(buf[0]) );
                debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
                rc = Win32PrtWrite( &lf, 1 );
            }
            else
#endif /* NT */
            if ( lst ) {
                int rc;
                rc = fwrite( buf[0], 1, strlen(buf[0]), lst );
                debug(F111,"txt2ps_char","fwrite rc",rc);
                rc = fwrite( &lf, 1, 1, lst );
            }
            return;
        } else if (!proflg) {           /* Not Postscript, print prolog. */
            doprolog();
        }
    }
    if (linesize[0] < 0) {              /* If line is empty, */
        blank++;                        /* just count it. */
        return;
    }
    if (blank > 0) {                    /* Any previous blank lines? */
        if (blank == 1) {               /* One */
#ifdef NT
        if ( winprint ) {
            int rc;
            rc = Win32PrtWrite( "()S\n", 4 );
            debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
        }
        else
#endif /* NT */
        if ( lst ) {
            int rc;
            rc = fwrite( "()S\n", 1, 4, lst );
            debug(F111,"txt2ps_char","fwrite rc",rc);
        }
        }
        else {                          /* Many */
            CHAR buf[16];
            sprintf(buf,"%d L\n",blank);        /* safe */
#ifdef NT
        if ( winprint ) {
            int rc;
            rc = Win32PrtWrite( buf, strlen(buf) );
            debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
        }
        else
#endif /* NT */
        if ( lst ) {
            int rc;
            rc = fwrite( buf, 1, strlen(buf), lst );
            debug(F111,"txt2ps_char","fwrite rc",rc);
        }
        }
    }
    line += blank;                      /* Count the blank lines */
    blank = 0;                          /* Reset blank line counter */

    wraps = maxhpos / ps_width;         /* Number of times line will wrap */
    if (wraps > ps_length) wraps = ps_length;   /* (within reason) */

    for (k = 0; k <= wraps; k++) {      /* For each wrapped line */
        m = k * ps_width;                       /* Starting position in buffer */
        for (i = 0; i <= bufs[k]; i++) { /* For each overstrike buffer */
            y = linesize[i] + 1;        /* Actual character count */
            if (y <= m)                 /* Nothing there, next buffer. */
              continue;
            /* Ending position of this wrap region in buffer. */
            n = (y < m + ps_width) ? y : m + ps_width;
            q = outbuf;
            *q++ = '(';                 /* Start text arg */
            for (j = m, p = buf[i]+m; j < n; j++) { /* For each character */
                c = *p++;
                if (c == '(' || c == ')' || c =='\\') /* Quote specials */
                  *q++ = '\\';          /*  with backslash. */
                if ((int) c < 128)      /* Insert 7-bit character literally */
                  *q++ = c;
                else {                  /* Insert 8-bit character */
                    *q++ = '\\';        /* as octal backslash ps_escape */
                    *q++ = (c >> 6) + '0'; /* (this avoids call to sprintf) */
                    *q++ = ((c >> 3) & 07) + '0';
                    *q++ = (c & 07) + '0';
                }
            }
            *q = '\0';
#ifdef NT
            if ( winprint ) {
                int rc;
                rc = Win32PrtWrite( outbuf, strlen(outbuf) );
                if ( i == bufs[k] )
                    rc = Win32PrtWrite( ")S\n", 3 );
                else
                    rc = Win32PrtWrite( ")U\n", 3 );
                debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
            }
            else
#endif /* NT */
            if ( lst ) {
                int rc;
                rc = fwrite( outbuf, 1, strlen(outbuf), lst );
                if ( i == bufs[k] )
                    rc = fwrite( ")S\n", 1, 3, lst );
                else
                    rc = fwrite( ")U\n", 1, 3, lst );
                debug(F111,"txt2ps_char","fwrite rc",rc);
            }
        }
    }
    clearbuf();                         /* Clear line buffer */
    line += wraps + 1;                  /* Increment line number */
    if (line > (ps_length - 1)) {               /* If page is full */
        newpage();                      /* print it and start new one */
        pagefull = 1;
    }
}

void
newpage() {                             /* Print current page, start new one */
    CHAR buf[80];
    if (pagefull) {                     /* If we just overflowed onto a */
        pagefull = 0;                   /* new page, but then got a formfeed */
        return;                         /* immediately after... */
    }
    if (!proflg)                        /* Do prolog if not done already */
      doprolog();                       /*  (in case file starts with ^L) */
    if (hpos)                           /* Add any partial line */
      addline();
    line = hpos = 0;                    /* Reset line, advance page */
    page++;
    sprintf(buf,"EndPage\n%%%%Page: %d %d\nStartPage\n",page,page); /* safe */
#ifdef NT
    if ( winprint ) {
        int rc;
        rc = Win32PrtWrite( buf, strlen(buf) );
        debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
    }
    else
#endif /* NT */
    if ( lst ) {
        int rc;
        rc = fwrite( buf, 1, strlen(buf), lst );
        debug(F111,"txt2ps_char","fwrite rc",rc);
    }
    blank = 0;
}

VOID
txt2ps_begin()
{
    hpos = line = psflag = 0;           /* Initialize these... */
    maxhpos = 0, pagefull = 0, proflg = 0, shift = 0;
    ps_escape = blank = 0;
    page = 1;

    clearbuf();                         /* Clear line buffer. */
}

VOID
txt2ps_end()
{
    CHAR buf[80];
    if (!psflag) {                      /* Done. If not postscript already, */
        if (hpos)                       /* if last line was not empty, */
          addline();                    /* add it to the page. */
        if (page != 1 || line != 0) {   /* Add trailer. */
            sprintf(buf,"EndPage\n%%%%Trailer\n%%%%Pages: %d\n",page); /* safe */
#ifdef NT
            if ( winprint ) {
                int rc;
                rc = Win32PrtWrite( buf, strlen(buf) );
                debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
            }
            else
#endif /* NT */
            if ( lst ) {
                int rc;
                rc = fwrite( buf, 1, strlen(buf), lst );
                debug(F111,"txt2ps_char","fwrite rc",rc);
            }
        }
    }
}

VOID
txt2ps_char(CHAR c)
{
    if (psflag) {                       /* File already postscript? */
#ifdef NT
        if ( winprint ) {
            int rc;
            rc = Win32PrtWrite( &c, 1 );
            debug(F111,"txt2ps_char","Win32PrtWrite rc",rc);
        }
        else
#endif /* NT */
        if ( lst ) {
            int rc;
            rc = fwrite( &c, 1, 1, lst );
            debug(F111,"txt2ps_char","fwrite rc",rc);
        }
        return;
    }

#ifdef ESCSEQ
    if (ps_escape) {                       /* Swallow ANSI ps_escape sequences */
        switch (ps_escape) {
        case 1:                 /* ESC */
            if (c < 040 || c > 057) /* Not intermediate character */
                ps_escape = 0;
            continue;
        case 2:                 /* CSI */
            if (c < 040 || c > 077)     /* Not parameter or intermediate */
                ps_escape = 0;
            continue;
        default:                        /* Bad ps_escape value, */
            ps_escape = 0;         /* shouldn't happen. */
            break;
        }
    }
#endif /* ESCSEQ */

    if (shift && c > 31 && c < 127)
        c |= 0200;                      /* Handle shift state. */

    if (pagefull && c != 014)   /* Spurious blank page suppression */
        pagefull = 0;

    switch (c) {                        /* Handle the input character */
    case 010:                   /* Backspace */
        hpos--;
        if (hpos < 0) hpos = 0;
        return;

    case 011:                   /* Tab */
        hpos = (hpos | 7) + 1;
        return;

    case 012:                   /* Linefeed */
        addline();                      /* Add the line to the page */
        return;

    case 014:                   /* Formfeed */
        newpage();                      /* Print current page */
        return;

    case 015:                   /* Carriage return */
        hpos = 0;                       /* Back to left margin */
        return;

    case 016:                   /* Shift-Out */
        shift = 1;                      /* Set shift state */
        return;

    case 017:                   /* Shift-In */
        shift = 0;                      /* Reset shift state */
        return;

#ifdef ESCSEQ                           /* Swallow ANSI ps_escape sequences */
/*
  1 = ANSI ps_escape sequence
  2 = ANSI control sequence
*/
    case 033:                   /* ESC or 7-bit CSI */
        ps_escape = ((c = getchar()) == 0133) ? 2 : 1;
        if (c != 033 && c != 0133 && c != 233) /* Not ANSI after all */
            ungetc(c,stdin);            /* put it back, avoid loops */
        return;

    case 0233:                  /* 8-bit CSI */
        if (charset == LATIN1) {
            ps_escape = 2;         /* 0233 is graphic char on PC, etc */
            return;
        }                               /* Otherwise fall thru & print it */
#endif /* ESCSEQ */

    default:
        addchar(c);
    }
}


void
printeron() {
    extern int noprinter, printertype;
    extern char * printsep;

    debug(F111,"printeron()","printon",printon);
    debug(F111,"printeron()","noprinter",noprinter);
    debug(F111,"printeron()","printertype",printertype);
    debug(F110,"printeron() printsep",printsep,0);

    printerclose_t = 0;

    if (printon || noprinter || printertype == PRT_NON)
        /* It's already on or should be ignored */
        return;

    if (printeropen()) {                /* Open OK? */

#ifndef NOLOCAL
        if ( !savefiletext[0] )
          ckstrncpy(savefiletext,filetext,sizeof(filetext));
        if ( is_xprint() )
          ckstrncpy(filetext,"CTRL PRINT",sizeof(filetext));
        else if ( is_cprint() )
            ckstrncpy( filetext, "COPY PRINT",sizeof(filetext));
        else if ( is_aprint() )
          ckstrncpy(filetext,"AUTO PRINT",sizeof(filetext));
        else if ( is_uprint() )
          ckstrncpy(filetext,"USER PRINT",sizeof(filetext));
        else
            ckstrncpy(filetext, "PRINTER ON",sizeof(filetext));

        VscrnIsDirty(VTERM);  /* status line needs to be updated */
#endif /* NOLOCAL */
        printon = TRUE;                 /* and printer is on. */
    }
#ifndef NOLOCAL
    else {
        char errormsg[MAXTERMCOL];
        debug(F100,"printeron() failed","",0);
        ckmakmsg(errormsg,sizeof(errormsg),
                 " ERROR: Unable to open device \"",
                 printername?printername:"prn","\"",NULL );
        popuperror(vmode,errormsg);
    }
#endif /* NOLOCAL */

    /* if there is a separator page, print it */
    if ( printsep ) {
        FILE * file = fopen(printsep,"rb");
        char   buf[512];
        int    count=0;

        if ( file ) {
            while ((count = fread(buf,sizeof(char),512,file)) > 0)
                prtstr(buf,count);
            fclose(file);
        }
    }
}

void
printeroff() {                          /* Turn off printer */
    extern char * printterm;
    extern int    printtimo;
    debug(F111,"printeroff()","printon",printon);
    debug(F110,"printeroff() printterm",printterm,0);
    debug(F111,"printeroff()","printtimo",printtimo);

    if (!printon)                       /* It's already off. */
      return;

    if ( printterm ) {
        prtstr( printterm, strlen(printterm) );
    }

#ifdef BPRINT
    if ( !printbidi ) {
#endif /* BPRINT */
        if ( printtimo ) {
            printerclose_t = time(NULL) + printtimo;
        }
        else if ( !printerclose() )
            return;
#ifdef BPRINT
    }
#endif /* BPRINT */


    printon = FALSE;

#ifndef NOLOCAL
    if ( is_xprint() )
        ckstrncpy(filetext,"CTRL PRINT",sizeof(filetext));
    else if ( is_cprint() )
        ckstrncpy( filetext, "COPY PRINT",sizeof(filetext));
    else if ( is_aprint() )
        ckstrncpy(filetext,"AUTO PRINT",sizeof(filetext));
    else if ( is_uprint() )
        ckstrncpy(filetext,"USER PRINT",sizeof(filetext));
    else if (savefiletext[0]) {         /* Fix status line */
        ckstrncpy(filetext,savefiletext,sizeof(filetext));
        savefiletext[0] = NUL;
    }

    VscrnIsDirty(VTERM);  /* status line needs to be updated */
#endif /* NOLOCAL */
}

#ifndef NOLOCAL
int
is_noprint()
{
    if ( cprint )
        return(0);
    if ( xprint )
        return(0);
    if ( aprint )
        return(0);
    if ( uprint )
        return(0);
    return(1);
}

int
is_uprint()
{
    if ( cprint )
        return(0);
    if ( xprint )
        return(0);
    if ( aprint )
        return(0);
    if ( uprint )
        return(1);
    return(0);
}

int
is_aprint()
{
    if ( cprint )
        return(0);
    if ( xprint )
        return(0);
    if ( aprint )
        return(1);
    return(0);
}

int
is_cprint()
{
    if ( cprint )
        return(1);
    return(0);
}

int
is_xprint()
{
    if ( cprint )
        return(0);
    if ( xprint )
        return(1);
    return(0);
}
#endif /* NOLOCAL */

int
printeropen()
{
    extern int printertype;
#ifdef BPRINT
    if ( printbidi )
        return TRUE;
#endif /* BPRINT */

    if ( winprint || lst )              /* Already open? */
        return TRUE;

    if ( printertype == PRT_NON )
        return FALSE;

    if (!printername)                   /* If printer not redirected */
        lst = fopen("prn", "wb");       /* open the PRN device */
    else if ( printpipe || printertype == PRT_PIP ) {
        if ( !printpipe )
            printpipe = 1;
        lst = (FILE *) popen(printername, "wb" ) ;/* open the piped command */
    }
#ifdef NT
    else if (printertype == PRT_WIN) {
        if ( Win32PrtOpen( printername ) ) {
            debug(F111,"Win32PrtOpen",printername,1);
            winprint = TRUE;
            lst = (FILE *)-1;
        }
    }
#endif /* NT */
    else if ( printertype == PRT_DOS ) {
#ifdef NT
        HANDLE hPrt;
        lst = fopen(printername, "ab"); /* open the file in append mode. */
        if ( lst ) {
            hPrt = (HANDLE)_get_osfhandle(_fileno(lst));
            if ( hPrt != INVALID_HANDLE_VALUE ) {
                prtcfg(hPrt);
            }
        }
#else /* NT */
        lst = fopen(printername, "ab"); /* open the file in append mode. */
#endif /* NT */
    } else if ( printertype == PRT_FIL ) {
        lst = fopen(printername, "ab"); /* open the file in append mode. */
    }

    if ( txt2ps )                       /* Init Txt2PS conversions */
        txt2ps_begin();

    return (lst || winprint);
}

int
printerclose()
{
    extern int printertype;

    printerclose_t = 0;   /* printerclose no longer needs to be called */

    if ( txt2ps )
        txt2ps_end();                   /* Complete Txt2PS conversions */

#ifdef BPRINT
    if ( printbidi )
        return FALSE;
#endif /* BPRINT */

    if ( !(winprint || lst) )           /* Printer Closed? */
        return TRUE;

#ifdef NT
    if ( printertype == PRT_WIN && winprint ) {
        int rc = Win32PrtClose();
        debug(F111,"Win32PrtClose",printername,rc);
        winprint = FALSE;
        lst = NULL;
    }
    else
#endif
    if (lst)
    {
        if ( printpipe && printertype == PRT_PIP )
        {
            pclose(lst);
        }
        else if ( printertype == PRT_DOS || printertype == PRT_FIL )
            fclose(lst);
        lst = NULL;
    }
    return !(winprint || lst);
}

void
prtchar( BYTE c )
{
    int turnoffprinter = FALSE ;
    int rc = 0;

    debug(F101,"prtchar","",c);
#ifdef BPRINT
    if ( printbidi ) {
        rc = bprtwrite( &c, 1 );
        debug(F111,"prtchar","bprtwrite rc",rc);
        return;
    }
#endif /* BPRINT */

    if (printon == FALSE)           /* Printer already on? */
    {
        printeron() ;               /* Turn on printer */
        turnoffprinter = TRUE ;     /* Remember to turn it off */
    }

    if ( txt2ps ) {
        txt2ps_char(c);
    } else
#ifdef NT
    if ( winprint ) {
        rc = Win32PrtWrite( &c, 1 );
        debug(F111,"prtchar","Win32PrtWrite rc",rc);
    }
    else
#endif /* NT */
    if ( lst ) {
        rc = fwrite( &c, 1, 1, lst );
        debug(F111,"prtchar","fwrite rc",rc);
    }

    if ( turnoffprinter )
        printeroff();
}

void
prtstr( char * s, int len )
{
    int turnoffprinter = FALSE ;
    int rc = 0;

    debug(F111,"prtstr",s,len);

#ifdef BPRINT
    if ( printbidi ) {
        rc = bprtwrite( s, len );
        debug(F111,"prtstr","bprtwrite rc",rc);
        return;
    }
#endif /* BPRINT */

    if (printon == FALSE)                       /* Printer already on? */
    {
        printeron() ;               /* Turn on printer */
        turnoffprinter = TRUE ;     /* Remember to turn it off */
    }

    if ( txt2ps ) {
        int i = 0;
        for ( ;i<len;i++ )
            txt2ps_char(s[i]);
    } else
#ifdef NT
    if ( winprint ) {
        rc = Win32PrtWrite( s, len );
        debug(F111,"prtstr","Win32PrtWrite rc",rc);
    }
    else
#endif /* NT */
    if ( lst ) {
        rc = fwrite( s, 1, len, lst );
        debug(F111,"prtstr","fwrite rc",rc);
    }

    if ( turnoffprinter )
        printeroff();
}

void
prtfile( char * filename )
{
    FILE * file=NULL;
    char   buf[512];
    int    count=0;
    int turnoffprinter = FALSE ;

    debug(F110,"prtfile",filename,0);

    if (printon == FALSE)           /* Printer already on? */
    {
        printeron() ;               /* Turn on printer */
        turnoffprinter = TRUE ;     /* Remember to turn it off */
    }

    file = fopen(filename,"rb");
    if ( file ) {
        while ((count = fread(buf,sizeof(char),512,file)) > 0) {
            if ( txt2ps ) {
                int i = 0;
                extern int fcharset;
                USHORT uch;
                int charset;

                charset = fc2tx( fcharset );

                for ( ;i<count;i++ ) {
                    if ( charset >= 0 ) {
                        uch = xl_u[charset](buf[i]);
                        txt2ps_char(xl_tx[TX_8859_1](uch));
                    } else
                        txt2ps_char(buf[i]);
                }
            } else
                prtstr(buf,count);
        }
        fclose(file);
    }

    if ( turnoffprinter )
        printeroff();
}

#ifndef NOLOCAL
/* ----------------------------------------------------------------- */
/* PrtLine - Copy the specified line on screen to printer.           */
/* parameters = Line to print 1-based, terminating character.        */
/* ----------------------------------------------------------------- */
void
prtline(int line, unsigned short achar) {
    int    j;
    USHORT n;
    viocell cells[MAXTERMCOL];
    char    outbuf[MAXTERMCOL + 1];
    int     turnoffprinter = FALSE ;

    if (printon == FALSE)                       /* Printer already on? */
    {
        printeron() ;               /* Turn on printer */
        turnoffprinter = TRUE ;     /* Remember to turn it off */
    }

    if (printon) {                              /* If printer on */
        n = VscrnGetWidth(VTERM) * sizeof(viocell);     /* Line width, incl attributes */
        /* Internally, screen lines are 0-based, so "i-1". */
        memcpy(cells,VscrnGetCells(VTERM,line-1,vscrn[VTERM].cursor.p),n);

        for (j = 0; j < VscrnGetWidth(VTERM); j++) {    /* Strip away the attribute bytes */
            if ( ck_isunicode() )
            {
                if (GNOW->itol )
                    outbuf[j] = (*GNOW->itol)(cells[j].c);
            }
            else {
                outbuf[j] =(cells[j].c & 0xFF);
            }
        }

        for (j = VscrnGetWidth(VTERM) - 1; j >= 0; j--) /* Strip trailing blanks */
          if (outbuf[j] != SP)
            break;
        outbuf[j+1] = '\r';
        outbuf[j+2] = achar;
        outbuf[j+3] = NUL;              /* Terminate string with NUL */
        if ( ISTVI(tt_type_mode) || ISWYSE(tt_type_mode) )
            prtstr(outbuf,strlen(outbuf)+1);        /* Print the NUL */
        else
            prtstr(outbuf,strlen(outbuf));
    }

    if ( turnoffprinter )
        printeroff();
}

/* ----------------------------------------------------------------- */
/* PrtPage - Copy lines on page to printer.                          */
/* parameters = Top line to print, bottom line to print, 1-based.    */
/* ----------------------------------------------------------------- */
void
prtpage(BYTE vmode, int top, int bot, int page) {
    int    i, j, ch;
    USHORT n;
    viocell cells[MAXTERMCOL];
    char    outbuf[MAXTERMCOL + 1];
    int     turnoffprinter = FALSE ;

    if (top < 1 || bot > VscrnGetHeight(vmode)-(tt_status[vmode]?1:0))         /* Args out of bounds? */
      return;

    if (printon == FALSE)                       /* Printer already on? */
    {
        printeron() ;               /* Turn on printer */
        turnoffprinter = TRUE ;     /* Remember to turn it off */
    }

    if (printon) {                              /* If printer on */
        n = VscrnGetWidth(vmode) * sizeof(viocell);     /* Line width, incl attributes */
        for (i = top-1; i < bot; i++) {  /* For each screen line, i... */
            /* Internally, screen lines are 0-based, so "i-1". */

            if (scrollflag[vmode]&& tt_roll[vmode])
              memcpy(cells,
                     VscrnGetCells(vmode,
                                   VscrnGetPageScrollTop(vmode, FALSE, page)
                                        -VscrnGetTop(vmode, FALSE, TRUE)+i,
                                   page),
                     n) ;
            else
              memcpy(cells,VscrnGetCells(vmode,i,page),n);

            for (j = 0; j < VscrnGetWidth(vmode); j++) { /* Strip away the attribute bytes */
                if ( ck_isunicode() )
                {
                    ch = (xl_tx[prncs])(cells[j].c);
                }
                else {
#ifndef COMMENT
                    ch = (xl_tx[prncs])((xl_u[tcsl])(cells[j].c & 0xFF));
#else /* COMMENT */
                    ch =(cells[j].c & 0xFF);
#endif /* COMMENT */
                }
                outbuf[j] = (ch >= 0 ? ch : '?');
            }

            for (j = VscrnGetWidth(vmode) - 1; j >= 0; j--) /* Strip trailing blanks */
              if (outbuf[j] != SP)
                break;
            outbuf[j+1] = '\r';
            outbuf[j+2] = '\n';
            outbuf[j+3] = NUL;          /* Terminate string with NUL */
            if ( ISTVI(tt_type_mode) || ISWYSE(tt_type_mode) )
                prtstr(outbuf,strlen(outbuf)+1);        /* Print the NUL */
            else
                prtstr(outbuf,strlen(outbuf));
        }

        if ( xprintff )
            prtchar(FF);

        if ( turnoffprinter )
            printeroff();
    }
}

/* ----------------------------------------------------------------- */
/* PrtScreen - Copy lines on screen to printer.                      */
/* parameters = Top line to print, bottom line to print, 1-based.    */
/* ----------------------------------------------------------------- */
void
prtscreen(BYTE vmode, int top, int bot) {
    prtpage(vmode, top, bot, vscrn[vmode].view_page);
}

/* ------------------------------------------------------------------ */
/* End of Printer functions                                           */
/* ------------------------------------------------------------------ */

/*
   C H K A E S  --  Check ANSI Escape Sequence state.
   Previously used for both input and output, now (edit 190) used only
   for output of keystrokes.  Input is handled in cwrite().
*/
int
chkaes(int esc, char c) {
    if (c == CAN || c == SUB)           /* CAN and SUB cancel any sequence */
      esc = ES_NORMAL;
    else                                /* Otherwise */
      switch (esc) {                    /* enter state switcher */

        case ES_NORMAL:                 /* NORMAL state */
          if (c == ESC)                 /* Got an ESC */
            esc = ES_GOTESC;            /* Change state to GOTESC */
          break;                        /* Otherwise stay in NORMAL state */

        case ES_GOTESC:                 /* GOTESC state */
          if (c == '[')                 /* Left bracket after ESC is CSI */
            esc = ES_GOTCSI;            /* Change to GOTCSI state */
          else if (c == 'P' || (c > 0134 && c < 0140)) /* P, ], ^, or _ */
            esc = ES_STRING;            /* Switch to STRING-absorption state */
          else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
            esc = ES_NORMAL;            /* Back to normal */
          else if (c != ESC)            /* ESC in an escape sequence... */
            esc = ES_ESCSEQ;            /* starts a new escape sequence */
          break;                        /* Intermediate or ignored ctrl char */

        case ES_ESCSEQ:                 /* ESCSEQ -- in an escape sequence */
          if (c > 057 && c < 0177)      /* Final character '0' thru '~' */
            esc = ES_NORMAL;            /* Return to NORMAL state. */
          else if (c == ESC)            /* ESC ... */
            esc = ES_GOTESC;            /* starts a new escape sequence */
          break;                        /* Intermediate or ignored ctrl char */

        case ES_GOTCSI:                 /* GOTCSI -- In a control sequence */
          if (c > 077 && c < 0177)      /* Final character '@' thru '~' */
            esc = ES_NORMAL;            /* Return to NORMAL. */
          else if (c == ESC)            /* ESC ... */
            esc = ES_GOTESC;            /* starts over. */
          break;                        /* Intermediate or ignored ctrl char */

        case ES_STRING:                 /* Inside a string */
          if (c == ESC)                 /* ESC may be 1st char of terminator */
            esc = ES_TERMIN;            /* Go see. */
          break;                        /* Absorb all other characters. */

        case ES_TERMIN:                 /* May have a string terminator */
          if (c == '\\')                /* which must be backslash */
            esc = ES_NORMAL;            /* If so, back to NORMAL */
          else                          /* Otherwise */
            esc = ES_STRING;            /* Back to string absorption. */
      }
    return(esc);
}

char * 
protoString(void)
{
    static char buf[24];

    if ( viewonly )
       ckstrncpy( buf, "VIEW ONLY",sizeof(buf)) ;    
    else if ( ttyfd == -1
#ifdef CK_TAPI
         || (tttapi && ttyfd == -2) 
#endif /* CK_TAPI */
         ) {
        ckstrncpy(buf,"Not Connected",sizeof(buf));
    } else if ( !network )
        sprintf(buf, "Serial %ld", speed);         /* safe */
    else
        switch ( nettype ) {
#ifdef SUPERLAT
        case NET_SLAT:
            ckstrncpy(buf, "SuperLAT",sizeof(buf) ) ;
            break;
#endif /* SUPERLAT */

#ifdef DECNET
        case NET_DEC:
            switch ( ttnproto ) {
            case NP_LAT:
                ckstrncpy(buf, "DECnet LAT",sizeof(buf));
                break;
            case NP_CTERM:
                ckstrncpy(buf, "DECnet CTERM",sizeof(buf));
                break;
            default:
                ckstrncpy(buf, "DECnet",sizeof(buf));
                break;
            }
            break;
#endif /* DECNET */

#ifdef SSHBUILTIN
        case NET_SSH:
            ckstrncpy(buf, ssh_proto_ver(),sizeof(buf));
            break;
#endif /* SSHBUILTIN */

        case NET_TCPB:
            switch ( ttnproto ) {
            case NP_TELNET:
                ckstrncpy(buf, "TELNET",sizeof(buf));
#ifdef CK_AUTHENTICATION
                {
                    int ck_tn_authenticated(void);
                    if ( sstelnet ? TELOPT_U(TELOPT_AUTHENTICATION) :
                         TELOPT_ME(TELOPT_AUTHENTICATION) ) {
                        switch ( ck_tn_authenticated() ) {
                        case AUTHTYPE_KERBEROS_V4:
                            ckstrncat(buf,":K4",sizeof(buf));
                            break;
                        case AUTHTYPE_KERBEROS_V5:
                            ckstrncat(buf,":K5",sizeof(buf));
                            break;
                        case AUTHTYPE_SRP:
                            ckstrncat(buf,":SRP",sizeof(buf));
                            break;
                        case AUTHTYPE_NTLM:
                            ckstrncat(buf,":NTLM",sizeof(buf));
                            break;
#ifdef COMMENT
                        case AUTHTYPE_SSL:
                            /* Not really authentication */
                            ckstrncat(buf,":SSL",sizeof(buf));
                            break;
#endif /* COMMENT */
                        }
                    }
                }
#endif /* CK_AUTHENTICATION */
#ifdef CK_ENCRYPTION
                {
                    int ck_tn_encrypting(void);
                    int ck_tn_decrypting(void);
#ifdef CK_SSL
                    extern int tls_active_flag, ssl_active_flag;
#endif /* CK_SSL */

                    if ( TELOPT_ME(TELOPT_ENCRYPTION) ||
                         TELOPT_U(TELOPT_ENCRYPTION) ) {
                        switch ( (ck_tn_encrypting()?1:0) |
                                 (ck_tn_decrypting()?2:0))
                        {
                        case 0:
                            ckstrncat(buf,":pp",sizeof(buf));
                            break;
                        case 1:
                            ckstrncat(buf,":Ep",sizeof(buf));
                            break;
                        case 2:
                            ckstrncat(buf,":pD",sizeof(buf));
                            break;
                        case 3:
                            ckstrncat(buf,":ED",sizeof(buf));
                            break;
                        }
                    }
#ifdef CK_SSL
                    else if (tls_active_flag) {
                        ckstrncat(buf,":TLS",sizeof(buf));
                    } else if (ssl_active_flag) {
                        ckstrncat(buf,":SSL",sizeof(buf));
                    }
#endif /* CK_SSL */
                }
#endif /* CK_ENCRYPTION */
                break;
            case NP_RLOGIN:
                ckstrncpy(buf, "LOGIN",sizeof(buf));
                break;
            case NP_K4LOGIN:
                ckstrncpy(buf, "K4LOGIN",sizeof(buf));
                break;
            case NP_EK4LOGIN:
                ckstrncpy(buf, "EK4LOGIN",sizeof(buf));
                break;
            case NP_K5LOGIN:
                ckstrncpy(buf, "K5LOGIN",sizeof(buf));
                break;
            case NP_EK5LOGIN:
                ckstrncpy(buf, "EK5LOGIN",sizeof(buf));
                break;
            case NP_KERMIT:
                ckstrncpy(buf, "KERMIT",sizeof(buf));
                break;
            case NP_SSL:
	    case NP_SSL_RAW:
                ckstrncpy(buf, "SSL",sizeof(buf));
                break;
            case NP_TLS:
	    case NP_TLS_RAW:
                ckstrncpy(buf, "TLS",sizeof(buf));
                break;
            case NP_K5U2U:
                ckstrncpy(buf, "K5U2U",sizeof(buf));
                break;
            case NP_TCPRAW:
            default:
                ckstrncpy(buf, "TCP/IP",sizeof(buf));
                break;
            }
            break;
        case NET_PIPE:
            ckstrncpy(buf, "Named Pipe",sizeof(buf));
            break;
        case NET_BIOS:
            ckstrncpy(buf, "NetBIOS",sizeof(buf));
            break;
        case NET_FILE:
            ckstrncpy(buf, "FILE",sizeof(buf));
            break;
        case NET_PTY:
            ckstrncpy(buf, "PTY",sizeof(buf));
            break;
        case NET_CMD:
            ckstrncpy(buf, "COMMAND",sizeof(buf));
            break;
        case NET_DLL:
            ckstrncpy(buf, "DLL",sizeof(buf));
            break;
        default:
            ckstrncpy(buf, "(unknown)",sizeof(buf));
        }
    return(buf);
}

/* ------------------------------------------------------------------ */
/* ipadl25 - Make normal CONNECT-mode status line                     */
/* ------------------------------------------------------------------ */
void
ipadl25() {
    int i;

    vikinit() ;                         /* Update VIK Table */

    if ( IS97801(tt_type_mode) ) {
        if ( sni_chcode )
            ckstrncpy(usertext, "CH.CODE",(MAXTERMCOL) + 1);
        else
            ckstrncpy(usertext, "ch.code",(MAXTERMCOL) + 1);
        if ( sni_bitmode == 8 )
            ckstrncat(usertext,"-8",(MAXTERMCOL) + 1);
        else
            ckstrncat(usertext,"-7",(MAXTERMCOL) + 1);
    } else {
#ifdef DECLED
        ckstrncpy(usertext," ",(MAXTERMCOL) + 1);
        for ( i=0; i<4 ; i++)
            ckstrncat( usertext, decled[i] ? "\x0F " : "\x07 ",
                       (MAXTERMCOL) + 1) ;
#else /* DECLED */
        strncpy(usertext," K-95 ",(MAXTERMCOL) + 1);
#endif /* DECLED */
    }
#ifdef PCTERM
    if ( tt_pcterm ) {
        ckstrncat(usertext,"PCTERM",(MAXTERMCOL) + 1);
    } else
#endif /* PCTERM */
    if (debses) {
        ckstrncat(usertext,"DEBUG",(MAXTERMCOL) + 1);
    } else if (tt_type_mode > -1 && tt_type_mode <= max_tt) {
        ckstrncat(usertext,tt_info[tt_type_mode].x_name,(MAXTERMCOL) + 1);

        switch ( tt_kb_mode ) {
        case KBM_HE:
            ckstrncat(usertext,"-H",(MAXTERMCOL) + 1);
            break;
        case KBM_RU:
            ckstrncat(usertext,"-R",(MAXTERMCOL) + 1);
            break;
        case KBM_EM:
		case KBM_ME:
            ckstrncat(usertext,"-E",(MAXTERMCOL) + 1);
            break;
        case KBM_WP:
            ckstrncat(usertext,"-W",(MAXTERMCOL) + 1);
            break;
		case KBM_MM:
			ckstrncat(usertext,"-M",(MAXTERMCOL) + 1);
            break;
        }
    }

    if ( viewonly )
       ckstrncpy( filetext, "VIEW ONLY",sizeof(filetext)) ;
    else if (printon) {
        if ( is_xprint() )
            ckstrncpy( filetext, "CTRL PRINT" ,sizeof(filetext)) ;
        else if ( is_cprint() )
            ckstrncpy( filetext, "COPY PRINT",sizeof(filetext) ) ;
        else if ( is_aprint() )
            ckstrncpy( filetext, "AUTO PRINT",sizeof(filetext) ) ;
        else if ( is_uprint() )
            ckstrncpy( filetext, "USER PRINT",sizeof(filetext) ) ;
        else
            ckstrncpy(filetext,"PRINTER ON",sizeof(filetext));
    } else 
        ckstrncpy( filetext, protoString(), sizeof(filetext));

#ifdef PCTERM
    if ( tt_pcterm ) {
        strcpy(helptext,"Ctrl-CAPSLOCK to deactivate");        /* safe */
    } else
#endif /* PCTERM */
    if (ISVTNT(tt_type_mode) && ttnum != -1)
        strcpy(helptext, "No Help" ) ;
#ifndef NOKVERBS
    else if (vik.help > 255 && keyname(vik.help))
      ckmakmsg(helptext, sizeof(helptext), "Help: ", keyname(vik.help),
                NULL,NULL);
#endif /* NOKVERBS */
    else if ( tt_escape )
      sprintf(helptext, "Help: ^%c?", ctl(escape));     /* safe */
    else
        strcpy(helptext, "No Help" ) ;

#ifdef PCTERM
    if ( tt_pcterm ) {
        exittext[0] = '\0';
    } else
#endif /* PCTERM */
    if (ISVTNT(tt_type_mode) && ttnum != -1)
        strcpy(exittext, "No Exit" ) ;
#ifndef NOKVERBS
    else if (vik.exit > 255 && keyname(vik.exit))
        ckmakmsg(exittext, sizeof(exittext), esc_msg, " ", keyname(vik.exit), NULL);
#endif /* NOKVERBS */
    else if ( tt_escape )
        sprintf(exittext, "%s ^%c?", esc_msg, ctl(escape));     /* safe */
#ifndef NOKVERBS
    else if ( vik.quit > 255 && keyname(vik.quit) )
        ckmakmsg( exittext, sizeof(exittext), "Quit: ", keyname(vik.quit),
                  NULL, NULL);
#endif /* NOKVERBS */
    else
        strcpy( exittext, "No Exit" ) ;

   if ( viewonly )
      hostname[0] = '\0' ;
   else
   {
      if (!network) {
#ifndef NODIAL
         if ( d_name )
            strncpy(hostname, d_name, 40);
         else
#endif /* NODIAL */
            strncpy(hostname, ttname, 40);
#ifdef NT
         _strupr(hostname);
#else /* NT */
         strupr(hostname);
#endif /* NT */
      }
      else {
         strncpy(hostname, ttname, 40);
#ifdef CK_NETBIOS
         if ( ( nettype == NET_BIOS ) && ( *ttname == '*' ) )
            strncpy(hostname+1, NetBiosRemote, NETBIOS_NAME_LEN ) ;
#endif /* CK_NETBIOS */
      }
   }
    VscrnIsDirty(VTERM);  /* status line needs to be updated */
}

/*
   sendchar() simply sends a byte to the host.  No translation,
   no local echo buffer, no half-duplex mode.
*/
int
sendchar(unsigned char c) {
/*
   NOTE: ttoci() uses an ioctl() that has been observed to hang, inexplicably,
   on some systems (e.g. high-end PS/2s that haven't been rebooted in a month,
   and have been going back and forth between SLIP and Kermit.)  In fact,
   this was reported only once, and rebooting the system made the problem go
   away.

   A NEWER NOTE: As of 8 May 94, ttoci() uses DosWrite, but first does an
   ioctl() to make sure the connection is OK.  Hopefully, this combines the
   the benefits of both methods: failure detection, buffering, flow control.
*/
    int x;
    long wait = 0;
    con_event evt ;


/*
  Send a character to the serial line in immediate mode, checking to avoid
  overwriting a character already waiting to be sent.  If we fail, e.g. because
  FLOW is RTS/CTS and CTS is not on (like when modems are retraining), enter
  a retry loop up to the timeout limit.
*/
    x = ttoci(dopar(c));                /* Try to send the character */
    if (x > 0 ||                        /* Transmission error */
         x == -1) {                     /* Connection failed  */
        KEY k;
        int w, oldw;

        debug(F101,"sendchar blocked char","",c);
        oldw = 0;                       /* For updating status line once/sec */
        save_status_line();             /* Save current status line */
        escapestatus[VTERM] = TRUE ;
        do {
            w = (waittime - wait) / 1000L;
            if (w != oldw) {            /* Countdown timer in status line */
                oldw = w;
                sprintf(usertext, " TRANSMISSION BLOCKED: %d",w);       /* safe */
                helptext[0] = '\0';
                VscrnIsDirty(VTERM);  /* status line needs to be updated */
            }
            if (evtinbuf(VTERM) > 0) {          /* Is an event waiting? */
                evt = congev(VTERM,0);          /* Read it */
                switch (evt.type) {
                case key:
                    k = evt.key.scancode ;
                    break;
#ifndef NOKVERBS
                case kverb:
                    k = evt.kverb.id | F_KVERB ;
                    break;
#endif /* NOKVERBS */
                case macro:
                    if ( evt.macro.string )
                        free( evt.macro.string ) ;
                    k = -1;
                    break;
                case literal:
                    if ( evt.literal.string )
                        free( evt.literal.string ) ;
                    k = -1;
                    break;
                case csi:
                case esc:
                default:
                    k = -1 ;
                }
                debug(F101,"BLOCKED key","",k);
#ifndef NOKVERBS
                if (k == K_EXIT | F_KVERB) { /* Let them escape back... */
                    SetConnectMode(FALSE,CSX_ESCAPE);      /* this way */
                    return 0;
                } else if (k == (F_KVERB | K_QUIT)) {
                    hangnow = 1;
                    quitnow = 1;
                    strcpy(termessage, "Hangup and quit.\n");
                    SetConnectMode(FALSE,CSX_USERDISC);
                    return 0;
                } else
#endif /* NOKVERBS */
                    if ( tt_escape && k == escape) { /* or this way */
                    evt = congev(VTERM,0);              /* Read it */
                    switch (evt.type) {
                    case key:
                        k = evt.key.scancode ;
                        break;
#ifndef NOKVERBS
                    case kverb:
                        k = evt.kverb.id | F_KVERB;
                        break;
#endif /* NOKVERBS */
                    case macro:
                        if ( evt.macro.string )
                            free( evt.macro.string ) ;
                        k = -1;
                        break;
                    case literal:
                        if ( evt.literal.string )
                            free( evt.literal.string ) ;
                        k = -1;
                        break;
                    case csi:
                    case esc:
                    default:
                        k = -1 ;
                    }
                    if ((k == 'c') || (k == 'C') || (k == 3)) {
                        SetConnectMode(FALSE,CSX_ESCAPE);
                        return 0;
                    } else bleep(BP_WARN);
                } else bleep(BP_WARN);          /* Anything else, just beep. */
            }
            msleep(INTERVAL);           /* Sleep a bit */
            wait += INTERVAL;           /* Go round till limit exhausted */
            x = ttoci(dopar(c));        /* Try to send again */
        } while ((x > 0 || x == -1) && (wait < waittime)
            && (ttyfd != -1 && ttyfd != -2));
        restore_status_line();
        escapestatus[VTERM] = FALSE ;
    }
    if (x < 0 || wait >= waittime) {            /* Go back to prompt if we failed */
        while (evtinbuf(VTERM) > 0)
        {
            evt = congev(VTERM,0);      /* Flush any remaining typeahead */
            if ( evt.type == macro )
            {
                if ( evt.macro.string )
                    free( evt.macro.string ) ;
            }
            else if ( evt.type == literal ) {
                if ( evt.literal.string )
                    free( evt.literal.string );
            }
        }
        SetConnectMode(FALSE,CSX_IOERROR);
        if (network)
            sprintf(termessage,
                     "Can't transmit to network, error status: %d\n", x);       /* safe */
        else {
            ckmakxmsg(termessage, sizeof(termessage),
                      "Serial port blocked",
                     ( x & 0x01 /* TX_WAITING_FOR_CTS */ )
                     ? "\nTx waiting for CTS to be turned ON" : "",
                     ( x & 0x02 /* TX_WAITING_FOR_DSR  */ )
                     ? "\nTx waiting for DSR to be turned ON" : "",
                     ( x & 0x04 /* TX_WAITING_FOR_DCD */ )
                     ? "\nTx waiting for DCD to be turned ON" : "",
                     ( x & 0x08 /* TX_WAITING_FOR_XON */ )
                     ? "\nTx waiting because XOFF received" : "",
                     ( x & 0x10 /* TX_WAITING_TO_SEND_XON */ )
                     ? "\nTx waiting because XOFF transmitted" : "",
                     ( x & 0x20 /* TX_WAITING_WHILE_BREAK_ON */ )
                     ? "\nTx because BREAK is being transmitted" : "",
                     ( x & 0x40 /* TX_WAITING_TO_SEND_IMM */ )
                     ? "\nCharacter waiting to transmit immediately" : "",
                     ( x & 0x80 /* RX_WAITING_FOR_DSR */ )
                     ? "\nRx waiting for DSR to be turned ON" : "",
                       "\n", NULL, NULL );
        }
    }
    return 0;
}

void
sendcharduplex(unsigned char key, int no_xlate ) {
    unsigned char csave;
    CHAR * bytes = NULL;
    int count = 1,i=0;

    key &= cmdmsk;                      /* Do any requested masking */
    csave = key;

    /* HACK ALERT */
    /* The following reference to tt_kb_mode is done to try to allow */
    /* the russian and hebrew modes to work within the current       */
    /* architecture of K95.  The translation tables for Russian and  */
    /* Hebrew modes are hard coded values belonging to CP866 and     */
    /* CP862.  If they are translated, they will be destroyed.       */
    /* We also only make the change here since at the present time   */
    /* the translations are only single characters, and not strings. */

    debug(F111,"sendcharduplex","no_xlate",no_xlate);

    if ( !no_xlate &&                   /* Translating this string, and */
         os2_outesc == ES_NORMAL )      /* If not inside escape seq.. */
    {                                   /* Translate character sets */
        count = ltorxlat(key, &bytes);
        if ( count <= 0 ) {
            debug(F111,"sendcharduplex ltorxlat()","key",key);
            debug(F111,"sendcharduplex ltorxlat()","count",count);
            return;
        }
        key = bytes[0];
    }
    os2_outesc = chkaes( os2_outesc, key ) ;

    for (i=0 ;i<count;i++ ) {
        if ( i>0 ) {
            key = bytes[i];
        }

        if (sosi
#ifdef NETCONN
#ifdef TCPSOCKET
             || network && (IS_TELNET() && !TELOPT_ME(TELOPT_BINARY))
#endif /* TCPSOCKET */
#endif /* NETCONN */
             ) {
            /* Shift-In/Out selected? or not a BINARY Telnet session */
            if (cmask == 0177 || pmask == 0177) { /* In 7-bit environment? */
                if (key & 0200) {           /* 8-bit character? */
                    if (outshift == 0) {    /* If not shifted, */
                        sendchar(SO);       /* shift. */
                        outshift = 1;
                    }
                } else {
                    if (outshift == 1) {    /* 7-bit character */
                        sendchar(SI);       /* If shifted, */
                        outshift = 0;       /* unshift. */
                    }
                }
            }
        }

        key = key & cmask & pmask; /* Apply Kermit-to-host mask now. */
        if (key == CK_CR) {            /* Handle TERMINAL NEWLINE */
            int stuff = -1, stuff2 = -1;
            if (tnlm) {                     /* TERMINAL NEWLINE ON */
                stuff = LF;                 /* Stuff LF */
            }
#ifdef NETCONN
#ifdef TCPSOCKET
    /* TELNET NEWLINE MODE */
            if (network)
            {
                if (IS_TELNET())
                {
                    switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) { /* NVT or BINARY */
                    case TNL_CR:
                        break;
                    case TNL_CRNUL:
                        stuff2 = stuff ;
                        stuff  = NUL ;
                        break;
                    case TNL_CRLF:
                        stuff2 = stuff ;
                        stuff = LF ;
                        break;
                    }
                }
#ifdef RLOGCODE
                else if (IS_RLOGIN())
                {
                    switch (tn_b_nlm) { /* always BINARY */
                    case TNL_CR:
                        break;
                    case TNL_CRNUL:
                        stuff2 = stuff ;
                        stuff  = NUL ;
                        break;
                    case TNL_CRLF:
                        stuff2 = stuff ;
                        stuff = LF ;
                        break;
                    }
                }
#endif /* RLOGCODE */
#ifdef SSHBUILTIN
                else if (IS_SSH())
                {
                    switch (tn_b_nlm) { /* always BINARY */
                    case TNL_CR:
                        break;
                    case TNL_CRNUL:
                        stuff2 = stuff ;
                        stuff  = NUL ;
                        break;
                    case TNL_CRLF:
                        stuff2 = stuff ;
                        stuff = LF ;
                        break;
                    }
                }
#endif /* SSHBUILTIN */
            }
#endif /* TCPSOCKET */
#endif /* NETCONN */

            if (stuff > -1) {
                if ( network ) {                /* on a network we want to send  */
                    char crlf[3] ; int cnt=2 ;  /* both characters in one packet */
                    crlf[0] = dopar(key) ;       /* so we use ttol() instead of   */
                    crlf[1] = dopar(stuff) ;    /* sendchar()                    */
                    if (stuff2 > -1) {
                        cnt++ ;
                        crlf[2] = stuff2 ;
                    }

                    if ( wy_block ) {
                        le_puts(crlf,cnt);
                    } else {
                        ttol(crlf,cnt) ;
                    }
                    if (duplex && !wy_block) {
                        le_putchar(key);
                        le_putchar(stuff);
                        if (stuff2 > -1)
                            le_putchar(stuff2);
                    }
                    return ;                    /* we are done */
                }
                else  /* not network */
                {
                    sendchar(dopar(key));   /* Send the CR */
                    if (duplex) {               /* If local echoing... */
                        le_putchar(key);    /*   echo to screen */
                    }
                    key = stuff;
                    csave = key;
                }
            }
            else if (tt_crd && duplex) {    /* CR-DISPLAY CRLF & local echo */
                le_putchar(CK_CR);
                csave = LF;
                key = CK_CR;                   /* ... but only send a CR */
            }
        }
#ifdef TNCODE
        /* If user types the 0xff character (TELNET IAC), it must be doubled. */
        else
            if (dopar(key) == IAC && network && IS_TELNET())
                sendchar(IAC); /* and the other one just below. */
#endif /* TNCODE */

        sendchar(dopar(key));
        if (duplex) {
            le_putchar(csave);
        }
    }
}

int
sendchars(unsigned char * s, int len) {
    int x, i = 0;
    long wait = 0;
    con_event evt ;

    debug(F111,"sendchars","len of s",len);

/*
  Send a character to the serial line in immediate mode, checking to avoid
  overwriting a character already waiting to be sent.  If we fail, e.g. because
  FLOW is RTS/CTS and CTS is not on (like when modems are retraining), enter
  a retry loop up to the timeout limit.
*/

    if (tt_pacing > 0 &&                /* taking care of pacing   */
         !wy_block) {                   /* if everything goes well */
        x = len;
        for ( i=0 ; i<len ; i++ ) {
            if (ttoc(dopar(s[i])) <= 0)
            {
                x = i;
                break;
            }
            msleep(tt_pacing);
        }
    }
    else {
        if ( parity ) {
            for ( i=0 ; i<len ; i++ )
                s[i]=dopar(s[i]);
        }
        if ( wy_block ) {
            le_puts(s,len);
            x = len;
        }
        else
            x = ttol(s,len);                    /* Try to send the string */
    }
    if (x<len) {                                /* Transmission error */
        KEY k;
        int w, oldw;

        debug(F100,"sendchars blocked","",0);
        oldw = 0;                       /* For updating status line once/sec */
        save_status_line();             /* Save current status line */
        escapestatus[VTERM] = TRUE ;
        do {
            w = (waittime - wait) / 1000L;
            if (w != oldw) {            /* Countdown timer in status line */
                oldw = w;
                sprintf(usertext, " TRANSMISSION BLOCKED: %d",w);       /* safe */
                helptext[0] = '\0';
                VscrnIsDirty(VTERM);  /* status line needs to be updated */
            }
            if (evtinbuf(VTERM) > 0) {          /* Is an event waiting? */
                evt = congev(VTERM,0);          /* Read it */
                switch (evt.type) {
                case key:
                    k = evt.key.scancode ;
                    break;
#ifndef NOKVERBS
                case kverb:
                    k = evt.kverb.id | F_KVERB ;
                    break;
#endif /* NOKVERBS */
                case macro:
                    if ( evt.macro.string )
                        free( evt.macro.string ) ;
                    k = -1;
                    break;
                case literal:
                    if ( evt.literal.string )
                        free( evt.literal.string ) ;
                    k = -1;
                    break;
                case csi:
                case esc:
                default:
                    k = -1 ;
                }
                debug(F101,"BLOCKED key","",k);
#ifndef NOKVERBS
                if (k == (F_KVERB | K_EXIT)) { /* Let them escape back... */
                    SetConnectMode(FALSE,CSX_ESCAPE);      /* this way */
                    return 0;
                } else if (k == (F_KVERB | K_QUIT)) {
                    SetConnectMode(0,CSX_USERDISC);
                    hangnow = 1;
                    quitnow = 1;
                    strcpy(termessage, "Hangup and quit.\n");
                    return 0;
                } else
#endif /* NOKVERBS */
                    if (tt_escape && k == escape) { /* or this way */
                    evt = congev(VTERM,0);              /* Read it */
                    switch (evt.type) {
                    case key:
                        k = evt.key.scancode ;
                        break;
#ifndef NOKVERBS
                    case kverb:
                        k = evt.kverb.id | F_KVERB;
                        break;
#endif /* NOKVERBS */
                    case macro:
                        if ( evt.macro.string )
                            free( evt.macro.string ) ;
                        k = -1;
                        break;
                    case literal:
                        if ( evt.literal.string )
                            free( evt.literal.string ) ;
                        k = -1;
                        break;
                    case csi:
                    case esc:
                    default:
                        k = -1 ;
                    }
                    if ((k == 'c') || (k == 'C') || (k == 3)) {
                        SetConnectMode(FALSE,CSX_ESCAPE);
                        return 0;
                    }
                    else
                        bleep(BP_WARN);
                }
                else
                    bleep(BP_WARN);             /* Anything else, just beep. */
            }
            msleep(INTERVAL);           /* Sleep a bit */
            wait += INTERVAL;           /* Go round till limit exhausted */
            if ( x>0 ) {                /* Something was sent last time */
                s+=x ;                  /* So advance the pointer */
                len-=x ;                /* And reduce the length */
            }
            x = ttol(s,len);    /* Try to send again */
        } while ((x <= 0) && (wait < waittime));
        restore_status_line();
        escapestatus[VTERM] = FALSE ;
    }
    if (wait >= waittime) {             /* Go back to prompt if we failed */
        while (evtinbuf(VTERM) > 0)
        {
            evt = congev(VTERM,0);      /* Flush any remaining typeahead */
            if ( evt.type == macro && evt.macro.string )
                free( evt.macro.string ) ;
            else if ( evt.type == literal && evt.literal.string )
                free( evt.literal.string );
        }
        SetConnectMode(FALSE,CSX_IOERROR);
        x = 0 ;      /* ttol() doesn't return error status */
        if (network)
            sprintf(termessage,
                     "Can't transmit to network, error status: %d\n", x);
        else {
            ckmakxmsg(termessage, sizeof(termessage),
                      "Serial port blocked",
                     ( x & 0x01 /* TX_WAITING_FOR_CTS */ )
                     ? "\nTx waiting for CTS to be turned ON" : "",
                     ( x & 0x02 /* TX_WAITING_FOR_DSR  */ )
                     ? "\nTx waiting for DSR to be turned ON" : "",
                     ( x & 0x04 /* TX_WAITING_FOR_DCD */ )
                     ? "\nTx waiting for DCD to be turned ON" : "",
                     ( x & 0x08 /* TX_WAITING_FOR_XON */ )
                     ? "\nTx waiting because XOFF received" : "",
                     ( x & 0x10 /* TX_WAITING_TO_SEND_XON */ )
                     ? "\nTx waiting because XOFF transmitted" : "",
                     ( x & 0x20 /* TX_WAITING_WHILE_BREAK_ON */ )
                     ? "\nTx because BREAK is being transmitted" : "",
                     ( x & 0x40 /* TX_WAITING_TO_SEND_IMM */ )
                     ? "\nCharacter waiting to transmit immediately" : "",
                     ( x & 0x80 /* RX_WAITING_FOR_DSR */ )
                     ? "\nRx waiting for DSR to be turned ON" : "",
                       "\n", NULL, NULL );
        }
    }
    return 0;
}

void
sendcharsduplex(unsigned char * s, int len, int no_xlate ) {
    int i,j,n ;
    static unsigned char * sendbuf = NULL;
    static int buflen = 0;
    unsigned char * bufptr, *stuffptr ;
    CHAR * bytes = NULL;
    int count = 1;

    /* count number of CRs that might require stuffing of LFs */
    for ( i=0,n=0 ;i<len;i++ ) {
        if ( s[i] == CK_CR ) {
            n++;
        }
    }
    debug(F111,"sendcharsduplex","len of s",len);
    debug(F111,"sendcharsduplex","num of CRs",n);
    debug(F111,"sendcharsduplex","old buflen",buflen);
    debug(F111,"sendcharsduplex","no_xlate",no_xlate);

    if ( (tt_utf8 ? 3*len : (len+n+1)) > buflen && sendbuf != NULL ) {
        free(sendbuf);
        sendbuf = NULL;
        buflen = 0;
    }

    if ( sendbuf == NULL ) {
        sendbuf = (unsigned char *)malloc((tt_utf8 ? 3*len : (len+n+1)));
        if ( sendbuf == NULL )
            return;
        buflen = (tt_utf8 ? 3*len : (len+n+1));
    }
    debug(F111,"sendcharsduplex","new buflen",buflen);

   stuffptr = bufptr = sendbuf - 1 ;
   for ( i = 0 ; i < len ; i++ )
   {
       bufptr = ++stuffptr ;
       *bufptr = s[i] & cmdmsk;         /* Do any requested masking */

       if ( !no_xlate &&                /* If translating this string, and */
            os2_outesc == ES_NORMAL) {  /* If not inside escape seq.. */
           count = ltorxlat(*bufptr, &bytes);
           if ( count > 0 )
               *bufptr = bytes[0];
       }

       for ( j=0;j<count;j++ ) {
           if ( j>0 ) {
               bufptr = ++stuffptr;
               *bufptr = bytes[++j];
           }
           os2_outesc = chkaes( os2_outesc, *bufptr ) ;

       if (sosi
#ifdef NETCONN
#ifdef TCPSOCKET
            || (network && IS_TELNET() && !TELOPT_ME(TELOPT_BINARY))
#endif /* TCPSOCKET */
#endif /* NETCONN */
            ) {
        /* Shift-In/Out selected? or not a BINARY Telnet session */
           if (cmask == 0177 || pmask == 0177) { /* In 7-bit environment? */
               if (*bufptr & 0200) {            /* 8-bit character? */
                   if (outshift == 0) { /* If not shifted, */
                       /* sendchar(SO); /* shift. */
                       *(++stuffptr) = SO ;
                       outshift = 1;
                   }
               }
               else {
                   if (outshift == 1) { /* 7-bit character */
                       /* sendchar(SI); /* If shifted, */
                       *(++stuffptr) = SI ;
                       outshift = 0;    /* unshift. */
                   }
               }
           }
       }

       *bufptr = *bufptr & cmask & pmask; /* Apply Kermit-to-host mask now. */
       if (duplex && !wy_block) {
           le_putchar(*bufptr) ;
       }
       if (*bufptr == CK_CR) {             /* Handle TERMINAL NEWLINE */
           if (tnlm) {                  /* TERMINAL NEWLINE ON */
               *(++stuffptr) = LF;                      /* Stuff LF */
           }
#ifdef NETCONN
#ifdef TCPSOCKET
       /* TELNET NEWLINE MODE */
           if (network)
           {
               if (IS_TELNET())
               {
                   switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) { /* NVT or BINARY */
                   case TNL_CR:
                       break;
                   case TNL_CRNUL:
                       *(++stuffptr)  = dopar(NUL) ;
                       break;
                   case TNL_CRLF:
                       *(++stuffptr) = dopar(LF) ;
                       break;
                   }
               }
#ifdef RLOGCODE
               else if (IS_RLOGIN())
               {
                   switch (tn_b_nlm) { /* always BINARY */
                   case TNL_CR:
                       break;
                   case TNL_CRNUL:
                       *(++stuffptr)  = dopar(NUL) ;
                       break;
                   case TNL_CRLF:
                       *(++stuffptr) = dopar(LF) ;
                       break;
                   }
               }
#endif /* RLOGCODE */
#ifdef SSHBUILTIN
               else if (IS_SSH())
               {
                   switch (tn_b_nlm) { /* always BINARY */
                   case TNL_CR:
                       break;
                   case TNL_CRNUL:
                       *(++stuffptr)  = dopar(NUL) ;
                       break;
                   case TNL_CRLF:
                       *(++stuffptr) = dopar(LF) ;
                       break;
                   }
               }
#endif /* SSHBUILTIN */
           }
#endif /* TCPSOCKET */
#endif /* NETCONN */

           if ( duplex & tt_crd && !wy_block) { /* CR-DISPLAY CRLF & local echo */
               le_putchar(LF);
           }
       } /* CR */
#ifdef TNCODE
       else {
    /* If user types the 0xff character (TELNET IAC), it must be doubled. */
           if (dopar(*bufptr) == IAC && network && IS_TELNET())
               *(++stuffptr) = dopar(IAC); /* and the other one just below. */
       }
#endif /* TNCODE */
       *bufptr = dopar(*bufptr) ;

       } /* for (j) */
   }    /* for (i) */
    *(stuffptr+1) = '\0' ; /* add NULL for debug.log */
    debug(F111,"sendcharsduplex","len of sendbuf",strlen(sendbuf));
    sendchars( sendbuf, (stuffptr - sendbuf+1) ) ;
}


/*  S E N D E S C S E Q  --  Send ESC followed by the given string  */
/*
  Used for sending host-requested reports, as well as for sending
  F-keys, arrow keys, etc.  Translation, shifting, etc, are not issues here.
*/
int
sendescseq(CHAR *s) {
    unsigned char sendstr[50], * p  ;

    /* Handle 7-bit vs 8-bit escape sequences...*/

    if (send_c1 && ((*s == '[' || *s == 'O' || *s == 'P'))) /* 8-bit C1 controls... */
    {
       sendstr[0] = (*s++ ^ (CHAR) 0x40) | (CHAR) 0x80;
    }
    else                                /* Or 7-bit escape sequences... */
    {
        if ( ISDG200(tt_type) )
            sendstr[0] = XRS ;
        else
            sendstr[0] = ESC;
    }
    p = sendstr + 1 ;

    if (duplex && !wy_block) {          /* Half duplex, echo it to the */
        le_putchar(sendstr[0]);
    }

    for ( ; *s ; s++)
    {
        *p = *s ;
        p++ ;
        if (duplex && !wy_block) {
            le_putchar(*s);
        }
    }
    *p = '\0' ;   /* tack on a Null for debug.log */
    sendchars(sendstr,p-sendstr);
    return(0) ;
}



/*---------------------------------------------------------------------------*/
/* IsDoubleWidth -                                          | Page: Cursor   */
/*---------------------------------------------------------------------------*/
/* Determines if the specified line is a double-width line. Primarily Used to
 * find out how far the cursor can move horizontally. */
bool
isdoublewidth( unsigned short y )     /* based from 1 */
{
    return VscrnGetLineVtAttr(VTERM,y-1) & VT_LINE_ATTR_DOUBLE_WIDE ;
}

/*---------------------------------------------------------------------------*/
/* CursorNextLine -                                         | Page: Cursor   */
/*---------------------------------------------------------------------------*/
/* Moves the cursor to the first position some number of lines down. This will
 * be screen left if the cursor is currently outside the margins, or the left
 * margin if the cursor is currently inside the margins.
 *
 * As the cursors relationship to the margins is evaluated before moving it,
 * calling five times with a count of 1 may produce a different result from
 * calling it once with a count of 5.
 *
 * Parameters:
 *     scroll       If the scrollable area should scroll at the bottom margin.
 *     count        Number of lines down to move
 */
void
cursornextline(BOOL scroll, int count) {
    if ( decsasd == SASD_TERMINAL ) {
        /* Due to a log from dcombeer I am no longer sure that */
        /* cursornextline() or cursorprevline() is affected by */
        /* Origin mode                                         */

        if (vscrn_c_page_margin_bot(VTERM) > wherey[VTERM]) {
            int margin_left = 1;
            int y = wherey[VTERM] + count;
            if (relcursor && wherey[VTERM] < vscrn_c_page_margin_top(VTERM))
            {
                y = vscrn_c_page_margin_top(VTERM) + count;
            }

            if ( printon && is_aprint() ) {
                prtline( wherey[VTERM], LF ) ;
            }

            if (y >= vscrn_c_page_margin_top(VTERM) &&
                y <= vscrn_c_page_margin_bot(VTERM) &&
                wherex[VTERM] >= vscrn_c_page_margin_left(VTERM)) {
                margin_left = vscrn_c_page_margin_left(VTERM);
            }

            lgotoxy(VTERM, margin_left, y);
        } else if ( wy_autopage ) {
            if ( printon && is_aprint() ) {
                prtline( wherey[VTERM], LF ) ;
            }
            lgotoxy(VTERM, 1, vscrn_c_page_margin_top(VTERM));
        } else if (ISVT100(tt_type_mode) || ISANSI(tt_type_mode)) {
            if (!(relcursor && wherey[VTERM] == vscrn_c_page_margin_bot(VTERM)
                    && scroll))
            {
                wrtch(CK_CR);
                wrtch(LF);
            }
        }
    }
    else if ( (ISWYSE(tt_type_mode) || ISTVI(tt_type_mode)) && autoscroll
              && !protect && scroll){
        wrtch(CK_CR);
        wrtch(LF);
    }

    if ( wrapit )
        wrapit = FALSE;
}

/*---------------------------------------------------------------------------*/
/* CursorHPA                                                | Page: Cursor   */
/*---------------------------------------------------------------------------*/
/* Horizontal Position Absolute (HPA). Also, Cursor Horizontal Absolute (CHA).
 * Move cursor to specified horizontal position
 *
 * Parameters:
 *     x        Column to move cursor to
 */
void
cursorhpa(int x)
{
    int rmargin = VscrnGetWidth(VTERM);
    if ( x < 1 ) x = 1;
    if ( x > rmargin ) x = rmargin;

    if ( decsasd == SASD_STATUS )
        lgotoxy( VSTATUS, x, 1 );
    else
    {
        if (relcursor) {
            x += vscrn_c_page_margin_left(VTERM) - 1;
            rmargin = cursor_right_margin(VTERM);
        }

        if ( x > rmargin ) x = rmargin;
        lgotoxy( VTERM, x, wherey[VTERM] ) ;
    }
}

/* ------------------------------------------------------------------ */
/* CursorPrevLine -                                                   */
/* ------------------------------------------------------------------ */
void
cursorprevline(int count) {
    if ( printon && is_aprint() ) {
        prtline( wherey[VTERM], LF ) ;
    }
    if ( decsasd == SASD_TERMINAL ) {
        /* Due to a log from dcombeer I am no longer sure that */
        /* cursornextline() or cursorprevline() is affected by */
        /* Origin mode                                         */

        int y = wherey[VTERM];
        int margin_left = 1;
        int margin_top = 1;

        if (wherex[VTERM] >= vscrn_c_page_margin_left(VTERM) &&
            y >= vscrn_c_page_margin_top(VTERM))
        {
            margin_top = vscrn_c_page_margin_top(VTERM);
        }

        if (y >= vscrn_c_page_margin_top(VTERM) &&
            y <= vscrn_c_page_margin_bot(VTERM) &&
            wherex[VTERM] >= vscrn_c_page_margin_left(VTERM)) {
            margin_left = vscrn_c_page_margin_left(VTERM);
        }

        if (margin_top <= wherey[VTERM] - count)
            y -= count;
        else if ( wy_autopage )
            y = vscrn_c_page_margin_bot(VTERM);
        else
            y = margin_top;

        lgotoxy(VTERM, margin_left, y);
    }
    if ( wrapit )
        wrapit = FALSE;
}

/* ------------------------------------------------------------------ */
/* CursorUp -                                                         */
/* ------------------------------------------------------------------ */
void
cursorup(int wrap) {
    if ( printon && is_aprint() ) {
        prtline( wherey[VTERM], LF ) ;
    }
    if ( decsasd == SASD_TERMINAL ) {
        int margin_top = 1;
		/* ISVT100: Prior to K95 3.0 beta 8 the logic here was wrong. On
		 * a VT100 or newer (confirmed on a VT520 and via vttest), the cursor
		 * can not pass from inside to outside the margins via CUU. This
		 * function is also called by a bunch of other emulations for which I
		 * have no physical example or test suite. For those other emulations
		 * the prior behaviour is retained in case it happens to be correct for
		 * them.  -- DG, 2026-03-08  */
		if ((ISVT100(tt_type_mode) && cursor_in_margins(VTERM)) ||
			(!ISVT100(tt_type_mode) && relcursor)) {
		    margin_top = vscrn_c_page_margin_top(VTERM);
		}

        if (margin_top != wherey[VTERM]) {
            lgotoxy(VTERM, wherex[VTERM], wherey[VTERM] - 1);
        } else if ( wrap ||
                  ISWYSE(tt_type_mode) ||
                  ISTVI(tt_type_mode) ||
                  ISHZL(tt_type_mode) ||
                  ISDG200(tt_type_mode))
            lgotoxy(VTERM, wherex[VTERM],
                     (relcursor ? vscrn_c_page_margin_bot(VTERM) :
                       VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)));
    }
    if ( wrapit )
        wrapit = FALSE;
}

/* ------------------------------------------------------------------ */
/* CursorDown -                                                       */
/* ------------------------------------------------------------------ */
/* wrap: If the cursor should wrap to the top of the screen
 * obey_margins: If margins should be obeyed or not (VT100-compatible emulations
 * 				 only.
 */
void
cursordownex(int wrap, int obey_margins) {
    if ( decsasd == SASD_TERMINAL ) {
        bool in_lr_margins = wherex[vmode] >= vscrn_c_page_margin_left(vmode) &&
            wherex[vmode] <= vscrn_c_page_margin_right(vmode);
		/* As with cursorup (above), the logic here was wrong for DEC VT
		 * terminals prior to K95 3.0 beta 8. I'm not sure if the previous logic
		 * was correct for some other emulation I can't test that also uses this
		 * function, so prior behaviour is retained for non-VT emulations */
        if ( (ISVT100(tt_type_mode) &&
                (vscrn_c_page_margin_bot(VTERM) != wherey[VTERM] || !in_lr_margins
                    || !obey_margins)) ||
             (!ISVT100(tt_type_mode) && (relcursor ? vscrn_c_page_margin_bot(VTERM) :
                  VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)) > wherey[VTERM]))
        {
            if ( printon && is_aprint() ) {
                prtline( wherey[VTERM], LF ) ;
            }
            lgotoxy(VTERM,wherex[VTERM], wherey[VTERM] + 1);
        } else if ( wrap ||
                    ((ISWYSE(tt_type_mode) ||
                     ISTVI(tt_type_mode) ||
                     ISHZL(tt_type_mode) ||
                     ISDG200(tt_type_mode) ||
                     ISREGENT25(tt_type_mode)) &&
                    !autoscroll || protect || wy_autopage))
        {
            if ( printon && is_aprint() ) {
                prtline( wherey[VTERM], LF ) ;
            }
            lgotoxy(VTERM, wherex[VTERM], (relcursor ? vscrn_c_page_margin_top(VTERM) : 1));
        } else if ( (ISWYSE(tt_type_mode) || ISTVI(tt_type_mode) || ISREGENT25(tt_type_mode)) &&
                  autoscroll && !protect) {
            wrtch(LF);
        }
    }
    if ( wrapit )
        wrapit = FALSE;
}

void
cursordown(int wrap) {
	cursordownex(wrap, 1);
}

/* ------------------------------------------------------------------ */
/* CursorRight -                                                      */
/* ------------------------------------------------------------------ */
/* wrap: If the cursor should wrap to the top of the screen
 * obey_margins: If margins should be obeyed or not.
 */
void
cursorrightex(int wrap, int obey_margins) {
    if ( decsasd == SASD_STATUS ) {
        if (wherex[VSTATUS] < VscrnGetWidth(VTERM))
           lgotoxy(VSTATUS, wherex[VSTATUS]+1,1);
    }
    else {
        int margin_right = VscrnGetWidth(VTERM);

        /* Only obey the right margin if we're told to, and if the cursor is
         * within the vertical scroll region */
        if (obey_margins &&
            (wherey[VTERM] >= vscrn_c_page_margin_top(VTERM) &&
             wherey[VTERM] <= vscrn_c_page_margin_bot(VTERM) &&
             wherex[VTERM] <= vscrn_c_page_margin_right(VTERM)) )
        {
            margin_right = vscrn_c_page_margin_right(VTERM);
        }

        if (isdoublewidth(wherey[VTERM]))
        {
            margin_right /= 2;
        }

        if (wherex[VTERM] < margin_right )
            lgotoxy( VTERM, wherex[VTERM] + 1, wherey[VTERM]);
        else if ( wrap ||
                  ISUNIXCON(tt_type_mode) ||
                  ISWYSE(tt_type_mode) ||
                  ISTVI(tt_type_mode) ||
#ifdef COMMENT
                  ISHFT(tt_type_mode) ||
#endif /* COMMENT */
                  ISDG200(tt_type_mode)) {
            cursornextline(TRUE, 1);
            if ( wrapit ) {
                cursorright(0);
                wrapit = FALSE ;
            }
        }
    }
    if ( wrapit )
        wrapit = FALSE;
}


void
cursorright(int wrap)
{
    cursorrightex(wrap, 1);
}

/* ------------------------------------------------------------------ */
/* CursorTab  -                                                       */
/* ------------------------------------------------------------------ */
/* Moves the cursor one or more tab stops to the right. Used for both
 * HT (one tab stop) or, on the VT520, CHT (one or more tab stops).   */
void
cursortab(int count)
{
    int i = wherex[VTERM];
    while ( count ) {
        if (i < cursor_right_margin(VTERM))
        {
            do {
                i++;
                cursorright(0);
            } while ((htab[i] != 'T') &&
                      (i <= cursor_right_margin(VTERM)-1));
        }
        count--;
    }
    if (cursor_on_visible_page(VTERM)) {
        VscrnIsDirty(VTERM);
    }
}

/* ------------------------------------------------------------------ */
/* CursorLeft -                                                       */
/* ------------------------------------------------------------------ */
void
cursorleft(int wrap) {
    char dwl = isdoublewidth(wherey[VTERM]) ;

    if ( decsasd == SASD_STATUS ) {
        if (wherex[VSTATUS] > 1)
            lgotoxy( VSTATUS, wherex[VSTATUS] - 1, 1);
    }
    else {
        int margin_left = 1;
        if (wherey[VTERM] >= vscrn_c_page_margin_top(VTERM) &&
             wherey[VTERM] <= vscrn_c_page_margin_bot(VTERM) &&
             wherex[VTERM] >= vscrn_c_page_margin_left(VTERM) )
        {
            margin_left = vscrn_c_page_margin_left(VTERM);
            if (dwl)
            {
                margin_left /= 2;
            }
        }

        if (wherex[VTERM] > margin_left)
            lgotoxy( VTERM,
                     wherex[VTERM] - 1,
                     wherey[VTERM]);
        else if ( wrap ||
                  (ISUNIXCON(tt_type_mode) ||
#ifdef COMMENT
                    ISHFT(tt_type_mode) ||
#endif /* COMMENT */
                    ISWYSE(tt_type_mode) ||
                    ISTVI(tt_type_mode) ||
                    ISDG200(tt_type_mode))) {
            lgotoxy( VTERM,
                     ( dwl ? VscrnGetWidth(VTERM) / 2 : VscrnGetWidth(VTERM)),
                     wherey[VTERM] - 1 );
        }
    }
    if ( wrapit )
        wrapit = FALSE;
}



/*---------------------------------------------------------------------------*/
/* switch_to_page                                           | Page: n/a      */
/*---------------------------------------------------------------------------*/
/* Go to a specific page */
void
switch_to_page(BYTE vmode, int page, BOOL view_page_too) {
    int max_page = vscrn[vmode].page_count - 1;

	if (max_page == 0) return; /* No other pages, nothing to do */
    if (page > max_page) page = max_page;
    if (page < 0) page = 0;

    vscrn[vmode].cursor.p = page;
    if (view_page_too) vscrn[vmode].view_page = page;

    if (cursor_on_visible_page(VTERM)) {
        /* Disable scrollback if we're not on page 0 */
        if (page != 0) {
            tt_term_scroll = 0;

            /* If we were scrolled back, we're not anymore! */
            scrollflag[VTERM] = 0;
            scrollstatus[VTERM] = 0;
            ipadl25();
        } else {
            tt_term_scroll = 1;
        }

        /* If we were in mark mode, we're not anymore!*/
        markcancel(vmode);

        VscrnIsDirty(VTERM);

#ifndef KUI
        /* Give the console-mode render a moment to catch up, otherwise it
         * new page may not get drawn.*/
        msleep(50);
#endif /* KUI */
    }
}

/*---------------------------------------------------------------------------*/
/* to_alternate_buffer                                      | Page: n/a      */
/*---------------------------------------------------------------------------*/
#define ALTERNATE_BUFFER_PAGE(v) (vscrn[(v)].page_count - 1)

void
to_alternate_buffer(BYTE vmode) {
    int alt_buf_page = ALTERNATE_BUFFER_PAGE(vmode);

    if (vscrn[vmode].cursor.p == alt_buf_page) {
        /* Already on the alternate screen */
        return;
    }

    saved_cursor_page = vscrn[vmode].cursor.p;
    saved_view_page = vscrn[vmode].view_page;

    switch_to_page(vmode,
                   alt_buf_page,
                   TRUE);
}

/*---------------------------------------------------------------------------*/
/* on_alternate_buffer                                      | Page: n/a      */
/*---------------------------------------------------------------------------*/
BOOL
on_alternate_buffer(BYTE vmode) {
	if (!ISK95(tt_type_mode)) return FALSE;
	return vscrn[vmode].cursor.p == ALTERNATE_BUFFER_PAGE(vmode);
}

/*---------------------------------------------------------------------------*/
/* from_alternate_buffer                                    | Page: n/a      */
/*---------------------------------------------------------------------------*/
void
from_alternate_buffer(BYTE vmode) {
    if (saved_view_page == -1) return;

    if (vscrn[vmode].page_cursor_coupling) {
        switch_to_page(vmode, saved_view_page, TRUE);
    } else {
        /* Page cursor coupling is off. First call will set both the view and
         * the cursor to the view page. Then with the second call, we'll restore
         * the cursor to whatever page it was on before without affecting the
         * view page */
        switch_to_page(vmode, saved_view_page, TRUE);
        switch_to_page(vmode, saved_cursor_page, FALSE);
    }

    saved_view_page = -1;
    saved_cursor_page = -1;
}

/*---------------------------------------------------------------------------*/
/* set_alternate_buffer_enabled                             | Page: n/a      */
/*---------------------------------------------------------------------------*/
void
set_alternate_buffer_enabled(BYTE vmode, BOOL enabled) {
    vscrn[vmode].allow_alt_buf = enabled;
}

/*---------------------------------------------------------------------------*/
/* ttype_pages                                              | Page: n/a      */
/*---------------------------------------------------------------------------*/
/* Maximum number of pages each terminal gets - this is used when allocating
 * buffers to determine how many pages to allocate */
int ttype_pages() {
    int result;
    switch(tt_type) {
    case TT_VT320: /* TODO: REMOVE WHEN VT420 TERM TYPE ADDED */
    case TT_VT330:
    case TT_VT340:
    case TT_VT420:
        result = 6;
        break;
    case TT_VT520:
        result = 8;
        break;
    case TT_VT525:
    case TT_K95:
        result = 9;
        break;
    default:
        result = 1;
        break;
    }
    return result;
}

/*---------------------------------------------------------------------------*/
/* term_max_page                                            | Page: n/a      */
/*---------------------------------------------------------------------------*/
/* Maximum page number for a given terminal type
 * VT330/340 has 6 (pages 0-5)
 * VT420/510/520 has 8 (pages 0-7)
 * VT525 and K95 have 9 (pages 0-8) */
int term_max_page(BYTE vmode) {
    int max_allowed = vscrn[vmode].page_count;
    int result = vscrn[vmode].page_count;

    if (user_pages > 0 && user_pages < max_allowed) {
        max_allowed = user_pages;
    }

    switch(tt_type) {
    case TT_VT330:
    case TT_VT340:
        result = 5;
        break;
    case TT_VT520:
    case TT_VT420:
    case TT_VT320: /* TODO: REMOVE WHEN VT420 TERM TYPE ADDED */
        result = 7;
        break;
    case TT_VT525:
    case TT_K95:
        result = 8;
        break;
    default:
        result = 0;
        break;
    }

    if (decspma_max_page >= 0 && decspma_max_page < result)
        result = decspma_max_page;

    if (result < max_allowed)
        return result;

    return max_allowed - 1;
}


/*---------------------------------------------------------------------------*/
/* next_page                                                | Page: n/a      */
/*---------------------------------------------------------------------------*/
/* Go forward by the specified number of pages. If the page count is zero, then
 * we go forward one page. */
void
next_page(BYTE vmode, int count) {
    int page = vscrn[vmode].cursor.p;
    int max_page = term_max_page(vmode);

    if (max_page <= 0) max_page = 1;
    if (count <= 0) count = 1;
    page += count;

    if (page > max_page) page = max_page;

    switch_to_page(vmode, page, vscrn[vmode].page_cursor_coupling);
}

/*---------------------------------------------------------------------------*/
/* previous_page                                            | Page: n/a      */
/*---------------------------------------------------------------------------*/
/* Goes back to a previous page by the specified number of pages (count). If
 * count is zero, then we go back one page */
void
previous_page(BYTE vmode, int count) {
    int page = vscrn[vmode].cursor.p;
    int max_page = term_max_page(vmode);

    if (page > max_page) page = max_page;

    if (count <= 0) count = 1;
    page -= count;

    if (page < 0) page = 0;

    switch_to_page(vmode, page, vscrn[vmode].page_cursor_coupling);
}



/*---------------------------------------------------------------------------*/
/* ReverseScreen                                            | Page: All      */
/*---------------------------------------------------------------------------*/
void
reversescreen(BYTE vmode) {
    int         r, c, width, p;

	/* Reverse the content on *all* pages */
	for (p = 0; p < vscrn[vmode].page_count; p++) {

#ifdef ONETERMUPD
    	viocell *   cell=NULL ;

    	for (r = 0; r < VscrnGetHeight(vmode)-(tt_status[VTERM]?1:0); r++) {          /* Loop for each row */
        	width = VscrnGetPageLineWidth(vmode,r, p) ;
        	for (c = 0;c < width;c++) { /* Loop for each character in row */
            	cell = VscrnGetPageCell( vmode, c, r, p ) ;
            	cell->video_attr = byteswapcolors(cell->video_attr);
        	}
    	}
#else
   	 	if ( IsConnectMode() ) {  /* In Terminal Mode */
        	viocell *   cell=NULL ;

        	for (r = 0; r < VscrnGetHeight(vmode)-(tt_status[VTERM]?1:0); r++) {      /* Loop for each row */
            	width = VscrnGetPageLineWidth(vmode,r, p) ;
            	for (c = 0;c < width;c++) { /* Loop for each character in row */
                	cell = VscrnGetPageCell( vmode, c, r, p) ;
                	cell->video_attr = byteswapcolors(cell->video_attr);
                }
            }
        }
    	else {
        	int x =0;
        	USHORT          n=0;
        	viocell   cells[MAXSCRNCOL];

        	n = cmd_cols ;
        	for (r = 0; r < cmd_rows; r++) {        /* Loop for each row */
           		ReadCellStr(cells, &n, r, 0);        /* Read this row from the screen */
           		for (c = 0; c < cmd_cols; c++) {     /* Loop for each character in row */
                	cells[c].video_attr = swapcolors(cells[c].video_attr);
                }
            	WrtCellStr(cells, n, r, 0);  /* Write the row back. */
        	}
    	}
#endif /* ONETERMUPD */

	}
}

/* ------------------------------------------------------------------ */
/* FlipScreen                                                         */
/* ------------------------------------------------------------------ */
void                            /* Flip screen between */
flipscreen(BYTE vmode) {        /* tell Vscrn code to swap foreground     */
                               /* and background colors on screen update */
    if ( vmode == VTERM ) {
        decscnm = decscnm ? FALSE : TRUE ;
        defaultattribute =
            swapcolors(defaultattribute);
        underlineattribute =
            swapcolors(underlineattribute);
        italicattribute = swapcolors(italicattribute);
        reverseattribute=swapcolors(reverseattribute);
        graphicattribute=swapcolors(graphicattribute);
		boldattribute=swapcolors(boldattribute);
		dimattribute=swapcolors(dimattribute);
		blinkattribute=swapcolors(blinkattribute);
        crossedoutattribute=swapcolors(crossedoutattribute);
        attribute = swapcolors( attribute );
    } else if ( vmode == VCMD ) {
        colorcmd = swapcolors(colorcmd);
    }
    reversescreen(vmode);
}

/*---------------------------------------------------------------------------*/
/* savscrbk                                                 | Page: View     */
/*---------------------------------------------------------------------------*/
/* Saves scrollback Vscrn (vmode) to the file (name), either overwriting or
 * appending depending on the (disp) parameter.
 *
 * When term is TRUE, only what is currently visible on screen will be saved,
 * rather than the entire scrollback buffer.
 *
 * The last line in the scrollback buffer is not saved as that would prevent
 * append from working nicely.
 */
int
savscrbk(mode,name,disp,term) int mode; char * name; int disp; int term; {
    static struct filinfo xx;
    int savfil;

    zclose(ZMFILE);

    if (disp) {
        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
        xx.lblopts = 0;
        savfil = zopeno(ZMFILE,name,NULL,&xx);
    } else savfil = zopeno(ZMFILE,name,NULL,NULL);

    if (savfil) {
        int    i, j;
        USHORT n;
        viocell cells[MAXTERMCOL];
        char    outbuf[MAXTERMCOL + 1];
        ULONG   beg, top, end;

        beg = VscrnGetPageBegin(vmode, FALSE, 0);
        top = VscrnGetPageTop(mode, FALSE, 0);
        end = VscrnGetPageEnd(mode, FALSE, 0);

        n = VscrnGetWidth(mode) * sizeof(viocell);      /* Line width, incl attributes */
        for (i = term ? top : beg; i != end; i = (i+1)%VscrnGetPageBufferSize(mode,FALSE,0)) {
            /* For each scrollback line, i... */
            memcpy(cells,VscrnGetCells(mode,i-top,0),n);

            for (j = 0; j < VscrnGetWidth(mode); j++) { /* Strip away the attribute bytes */
                if ( ck_isunicode() )
                {
                    if (GNOW->itol )
                        outbuf[j] = (*GNOW->itol)(cells[j].c);
                }
                else {
                    outbuf[j] =(cells[j].c & 0xFF);
                }
                if (outbuf[j] == NUL)           /* Don't allow NULs in the stream */
                    outbuf[j] = SP;
            }

            for (j = VscrnGetWidth(mode) - 1; j >= 0; j--) /* Strip trailing blanks */
                if (outbuf[j] != SP)
                    break;
            outbuf[j+1] = NUL;          /* Terminate string with NUL */
            zsoutl(ZMFILE,outbuf);
        }
        zclose(ZMFILE);
        return(1);
    } else {
        return(0);
    }
}

int
pnumber(int *achar) {
    int num = 0;
    while (isdigit(*achar)) {           /* Get number */
        num = (num * 10) + (*achar) - 48;
            *achar = (escnext<=esclast)?escbuffer[escnext++]:0;
    }
    return (num);
}

/* ----------------------------------------------------------------- */
/* Clear Functions                                                   */
/* ----------------------------------------------------------------- */

cell_video_attr_t
geterasecolor( int vmode )
{
    cell_video_attr_t erasecolor = cell_video_attr_init_vio_attribute(0);

    switch ( vmode ) {
    case VSTATUS:
        if ( !ISVT220(tt_type_mode) ) {
            erasecolor = colorstatus ;
            break;
        }
        /* else fall through and act as VTERM */
    case VTERM:
        if ( erasemode == 0 ) {
            erasecolor = attribute ;
        }
        else {
            erasecolor = defaultattribute ;
        }
        break;

    case VCMD:
    default:
        erasecolor = colorcmd;
    }
    return erasecolor;
}

/*----------------------------------------------------------+----------------*/
/* clrpage                                                  | Page: Specified*/
/*----------------------------------------------------------+----------------*/
void
clrpage( BYTE vmode, CHAR fillchar, int page ) {
    /* This function becomes really simple with the new model
       since all we do is move the top of the screen down in
       the vscrn buffer by the size of the screen.
    */

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    if ( IS97801(tt_type_mode) ) {
        VscrnScrollPage(vmode,UPWARD,vscrn_page_margin_top(VTERM,page)-1,
                     	vscrn_c_page_margin_bot(VTERM)-1,
                     	-1, -1,
                     	vscrn_c_page_margin_bot(VTERM)-vscrn_page_margin_top(VTERM,page)+1,
                     	vscrn_c_page_margin_top(VTERM)==1 &&
                     	vscrn_c_page_margin_bot(VTERM)==(VscrnGetHeight(vmode)-(tt_status[vmode]?1:0)),
                     	fillchar,
						page);
    }
    else {
        VscrnScrollPage(vmode,UPWARD_JUMP,
                     	0,VscrnGetHeight(vmode)-(tt_status[vmode]?2:1),
                     	-1, -1,
                     	VscrnGetHeight(vmode)-(tt_status[vmode]?1:0),
                     	TRUE,fillchar, page);

#ifdef KUI
        if (ISDECTERM(tt_type_mode) || ISK95(tt_type_mode)) {
            videoline *line = NULL, *newline = NULL ;
            int y = 0, y2 = 0, linecount = VscrnGetBufferSize(vmode,TRUE,FALSE);
#ifndef PACKED_CELL_ATTRS
            int x = 0;
#endif /* PACKED_CELL_ATTRS */

            /* Now we must restore any ruled lines */
            for ( y = linecount - VscrnGetHeight(vmode) + (tt_status[vmode]?1:0)
                    ; y < linecount ; y++,y2++ )
            {
                line = VscrnGetLineFromTop( vmode, y, FALSE ) ;
                newline = VscrnGetLineFromTop( vmode, y2, FALSE ) ;
#ifdef PACKED_CELL_ATTRS
                memcpy(newline->cell_attrs, line->cell_attrs,
                    sizeof(vt_cell_attr_t) * CELL_ATTR_LEN);
#else /* PACKED_CELL_ATTRS */
                for ( x = 0 ; x < CELL_ATTR_LEN ; x++ ) {
                    /* Only preserve ruled line attributes */
                    newline->cell_attrs[x] = line->cell_attrs[x] & CA_ATTR_RULED_LINES;
                }
#endif /* PACKED_CELL_ATTRS */
            }
        }
#endif /* KUI */
    }
}

/*----------------------------------------------------------+----------------*/
/* clrscreen                                                | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
void
clrscreen( BYTE vmode, CHAR fillchar ) {
    clrpage(vmode, fillchar, vscrn[vmode].cursor.p);
}

/*----------------------------------------------------------+----------------*/
/* clrtoeoln                                                | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clears from the current cursor position to the end of the line. This may
 * include the status line.
 *
 * While this function can be invoked by the user (via CLEAR TERMMINAL), it only
 * operates on the page the cursor is currently on (which may not be the page
 * currently on screen) as it clears from the cursors current position.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clrtoeoln( BYTE vmode, CHAR fillchar ) {
    int x ;
    videoline * line = NULL ;
    cell_video_attr_t cellcolor = geterasecolor(vmode);

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* take care of current line */
    line = VscrnGetLineFromTop( vmode, wherey[vmode]-1, FALSE ) ;
    for ( x=wherex[vmode]-1 ; x < MAXTERMCOL ; x++ )
        {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor ;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
        }
}

/*----------------------------------------------------------+----------------*/
/* clreoscr_escape                                          | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clears from the current cursor position to the end of the screen. This may
 * include the status line.
 *
 * While this function can be invoked by the user (via CLEAR TERMMINAL), it only
 * operates on the page the cursor is currently on (which may not be the page
 * currently on screen) as it clears from the cursors current position.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clreoscr_escape( BYTE vmode, CHAR fillchar ) {
    int x,y,h;
    videoline * line = NULL;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    if (wherex[vmode] == 1 && wherey[vmode] == 1) {
        clrscreen(vmode,fillchar);
        return;
    }

    RequestVscrnMutex(vmode, SEM_INDEFINITE_WAIT) ;
    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=wherex[vmode]-1 ; x <MAXTERMCOL ; x++ )
    {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
    }
    line->vt_line_attr = VT_LINE_ATTR_NORMAL ;

    /* now take care of additional lines */
    if ( IS97801(tt_type_mode) )
        h = vscrn_c_page_margin_bot(VTERM)-1;
    else
        h = VscrnGetHeight(vmode)-(tt_status[vmode]?1:0) ;
    for ( y=wherey[vmode] ; y<h ; y++)
    {
        line = VscrnGetLineFromTop(vmode, y, FALSE) ;
        for ( x=0 ; x <MAXTERMCOL ; x++ )
        {
            line->cells[x].c = fillchar ;
            line->cells[x].video_attr = cellcolor;
            line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
        }
        line->vt_line_attr = VT_LINE_ATTR_NORMAL ;
    }
    ReleaseVscrnMutex(vmode);
}

/*----------------------------------------------------------+----------------*/
/* clrboscr_escape                                          | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clears from the current cursor position to the beginning of the screen. This
 * may include the status line.
 *
 * While this function can be invoked by the user (via CLEAR TERMMINAL), it only
 * operates on the page the cursor is currently on (which may not be the page
 * currently on screen) as it clears from the cursors current position.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clrboscr_escape( BYTE vmode, CHAR fillchar ) {
    int x,y,h;
    videoline * line = NULL;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* now take care of first wherey[VTERM]-1 lines */
    if ( IS97801(tt_type_mode) )
        h = vscrn_c_page_margin_top(VTERM)-1;
    else
        h = 0;
    for ( y=h ; y<wherey[vmode]-1 ; y++ )
        {
        line = VscrnGetLineFromTop(vmode, y, FALSE) ;
        for ( x=0 ; x <MAXTERMCOL ; x++ )
            {
            line->cells[x].c = fillchar ;
            line->cells[x].video_attr = cellcolor;
            line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
            }
        line->vt_line_attr = VT_LINE_ATTR_NORMAL ;
        }

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=0 ; x < wherex[vmode] ; x++ )
        {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
        }
    line->vt_line_attr = VT_LINE_ATTR_NORMAL ;
}

/*---------------------------------------------------------------------------*/
/* clrregion                                                | Page: Cursor   */
/*---------------------------------------------------------------------------*/
void
clrregion( BYTE vmode, CHAR fillchar ) {
    /* This function becomes really simple with the new model
       since all we do is move the top of the screen down in
       the vscrn buffer by the size of the screen.
    */

    if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
         wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
        return;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    VscrnScroll(vmode,UPWARD,vscrn_c_page_margin_top(VTERM)-1,
                 vscrn_c_page_margin_bot(VTERM)-1,
                 vscrn_c_page_margin_bot(VTERM)-vscrn_c_page_margin_top(VTERM)+1,
                 vscrn_c_page_margin_top(VTERM)==1 &&
                 vscrn_c_page_margin_bot(VTERM)==(VscrnGetHeight(vmode)-(tt_status[vmode]?1:0)),
                 fillchar, FALSE) ;
}

/*----------------------------------------------------------+----------------*/
/* clreoreg_escape                                          | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clears to the end of the current region within set margins. If the cursor
 * is outside the set margins, no action is taken. Only used by SCO and
 * SNI-97801 emulations at this time.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clreoreg_escape( BYTE vmode, CHAR fillchar ) {
    int x,y,h;
    videoline * line = NULL;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
         wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
        return;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    if (wherex[vmode] == 1 && wherey[vmode] == 1) {
        clrscreen(vmode,fillchar);
        return;
    }

    RequestVscrnMutex(vmode, SEM_INDEFINITE_WAIT) ;
    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=wherex[vmode]-1 ; x <MAXTERMCOL ; x++ )
    {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
    }
    line->vt_line_attr = VT_LINE_ATTR_NORMAL ;

    /* now take care of additional lines */
    h = vscrn_c_page_margin_bot(VTERM)-1;
    for ( y=wherey[vmode] ; y<h ; y++)
    {
        line = VscrnGetLineFromTop(vmode, y, FALSE) ;
        for ( x=0 ; x <MAXTERMCOL ; x++ )
        {
            line->cells[x].c = fillchar ;
            line->cells[x].video_attr = cellcolor;
            line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
        }
        line->vt_line_attr = VT_LINE_ATTR_NORMAL ;
    }
    ReleaseVscrnMutex(vmode);
}

/*----------------------------------------------------------+----------------*/
/* clrboreg_escape                                          | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clears to the beginning of the current region within set margins. If the
 * cursor is outside the set margins, no action is taken. Only used by SCO and
 * SNI-97801 emulations at this time.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clrboreg_escape( BYTE vmode, CHAR fillchar ) {
    int x,y,h;
    videoline * line = NULL;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
         wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
        return;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* now take care of first wherey[VTERM]-1 lines */
    h = vscrn_c_page_margin_top(VTERM)-1;
    for ( y=h ; y<wherey[vmode]-1 ; y++ )
        {
        line = VscrnGetLineFromTop(vmode, y, FALSE) ;
        for ( x=0 ; x <MAXTERMCOL ; x++ )
            {
            line->cells[x].c = fillchar ;
            line->cells[x].video_attr = cellcolor;
            line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
            }
        line->vt_line_attr = VT_LINE_ATTR_NORMAL ;
        }

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=0 ; x < wherex[vmode] ; x++ )
        {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
        }
    line->vt_line_attr = VT_LINE_ATTR_NORMAL ;
}

/*----------------------------------------------------------+----------------*/
/* clrbol_escape                                            | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clears from the current cursor position to the beginning of the line. This
 * may include the status line.
 *
 * While this function can be invoked by the user (via CLEAR TERMMINAL), it only
 * operates on the page the cursor is currently on (which may not be the page
 * currently on screen) as it clears from the cursors current position.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clrbol_escape( BYTE vmode, CHAR fillchar ) {
    videoline * line = NULL ;
    int x ;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=0 ; x < wherex[vmode] ; x++ )
        {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
        }
}

/*----------------------------------------------------------+----------------*/
/* clreol_escape                                            | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clear from current cursor position to end of line. This may include the
 * status line.
 *
 * While this function can be invoked by the user (via CLEAR TERMMINAL), it only
 * operates on the page the cursor is currently on (which may not be the page
 * currently on screen) as it clears from the cursors current position.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clreol_escape( BYTE vmode, CHAR fillchar ) {
    videoline * line = NULL ;
    int x ;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=wherex[vmode]-1 ; x < MAXTERMCOL ; x++ )
    {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
    }
}

/*----------------------------------------------------------+----------------*/
/* clrline_escape                                           | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clear from current cursor position to end of line. This may include the
 * status line.
 *
 * While this function can be invoked by the user (via CLEAR TERMMINAL), it only
 * operates on the page the cursor is currently on (which may not be the page
 * currently on screen) as it clears from the cursors current position.
 *
 * Parameters:
 *  vmode
 *  	The screen buffer to operate on
 *	fillchar
 *		The character to fill (clear) with
 */
void
clrline_escape( BYTE vmode, CHAR fillchar ) {
    videoline * line = NULL ;
    int x ;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=0 ; x < MAXTERMCOL ; x++ )
    {
        line->cells[x].c = fillchar ;
        line->cells[x].video_attr = cellcolor;
        line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
    }
}

void
clrcol_escape( BYTE vmode, CHAR fillchar ) {
    int ys ;
    int x  = wherex[VTERM]-1 ;
    int y ;
    vtattrib vta ={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    viocell cell;

    cell.c = fillchar;
    cell.video_attr = geterasecolor(vmode);
    /* TODO: vta.erased = TRUE; ?
     *  Used by WYSE emulations to clear a column to a particular character, so
     * perhaps not?
     **/

    if ( fillchar == NUL )
        cell.c = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    if ( IS97801(tt_type_mode) ) {
        y = vscrn_c_page_margin_top(VTERM)-1;
        ys = vscrn_c_page_margin_bot(VTERM)-1;
    }
    else {
        ys = VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0);
        y = 0;
    }
    for ( ; y<ys ; y++ )
        VscrnWrtCell( VTERM, cell, vta, y, x ) ;
}

/*----------------------------------------------------------+----------------*/
/* clrrect_escape                                           | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
/* Clears a rectangle from current cursor position to row,col */
/* using fillchar.                                            */
void
clrrect_escape( BYTE vmode, int top, int left, int bot, int right, int fillchar )
{
    int startx, starty, endx, endy, l, x ;
    videoline * line = NULL ;
    bool fill = TRUE;
    cell_video_attr_t cellcolor = attribute ;
    int cell_attrib = vtattrib_to_int(attrib);

    if ( left < right ) {
        startx = left - 1 ;
        endx   = right - 1 ;
    }
    else {
        startx = right - 1 ;
        endx = left - 1 ;
    }

    if ( top < bot ) {
        starty = top - 1 ;
        endy   = bot - 1 ;
    }
    else {
        starty = bot - 1 ;
        endy = top - 1 ;
    }

    if ( fillchar == NUL ) {
        /* STD 070 says DECERA erases with Space characer, but the VT420 and 520
         * actually fill with the empty character, which we signal with the
         * Erased Attribute */
        fillchar = SP ;
        cell_attrib = VT_CHAR_ATTR_ERASED;
        cellcolor = geterasecolor(vmode);

        fill = FALSE;
    }
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* check to see if any of the lines are protected */
    /* if so, abort                                   */

    for ( l=starty ; l <= endy ; l++ )
        if ( VscrnGetLineFromTop( vmode, l, FALSE )->vt_line_attr & WY_LINE_ATTR_PROTECTED )
            return ;

    /* so now we just need to clear each row */

    for ( l=starty ; l <= endy ; l++ ) {
        line = VscrnGetLineFromTop( vmode, l, FALSE ) ;
        for ( x=startx ; x <= endx ; x++ )
        {
            /* If we're erasing, then leave erased cells as erased. If we're
             * just filling, then fill everything. */
            if (line->vt_char_attrs[x] != VT_CHAR_ATTR_ERASED || fill) {
                line->cells[x].c = fillchar ;
                line->vt_char_attrs[x] = cell_attrib ;
            }
            /* Erased cells still get their colour updated */
            line->cells[x].video_attr = cellcolor;
        }

    }
}

/* ----------------------------------------------------------------- */
/* Selective Clear Functions                                         */
/* ----------------------------------------------------------------- */

/*----------------------------------------------------------+----------------*/
/* selclrscreen                                             | Page: Cursor   */
/*----------------------------------------------------------+----------------*/
void
selclrscreen( BYTE vmode, CHAR fillchar ) {
    int             x=0, y=0, y2=0, linecount = VscrnGetBufferSize(vmode,TRUE,FALSE) ;
    videoline *     line=NULL, * newline = NULL ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    VscrnScroll(vmode,UPWARD,0,VscrnGetHeight(vmode)-(tt_status[vmode]?2:1),
                 VscrnGetHeight(vmode)-(tt_status[vmode]?1:0),TRUE,fillchar, FALSE);

    /* Okay, so now we have scrolled the screen.  But the protected */
    /* fields need to be copied back to the new current screen      */

    /* According to DEC STD 070, for VT terminals *all* attributes have to be
     * copied back: for DECSED, "The character rendition and attributes
     * associated with each position do not change"   - DG, 2026-03-31
     */

    for ( y = linecount - VscrnGetHeight(vmode) + (tt_status[vmode]?1:0) ;
          y < linecount ; y++,y2++ ) {
        line = VscrnGetLineFromTop( vmode, y, FALSE ) ;
        newline = VscrnGetLineFromTop( vmode, y2, FALSE ) ;
        for ( x = 0 ; x < MAXTERMCOL ; x++ )
        {
            /* I don't know if other emulations using this function behave as
             * DEC terminals do, so for now they get they prior behaviour */
            if (ISVT220(tt_type_mode)) {
                if ( line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) {
                    newline->cells[x] = line->cells[x] ;
                }
                newline->vt_char_attrs[x] = line->vt_char_attrs[x] ;
                newline->vt_line_attr = line->vt_line_attr;
#ifdef KUI
#ifndef PACKED_CELL_ATTRS
                if (ISDECTERM(tt_type_mode) || ISK95(tt_type_mode)) {
                    /* Only preserve ruled line attributes */
                    newline->cell_attrs[x] = line->cell_attrs[x] & CA_ATTR_RULED_LINES;
                }
#endif /* PACKED_CELL_ATTRS */
#endif /* KUI */
            }
            else {
                if ( line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) {
                    newline->cells[x] = line->cells[x] ;
                    newline->vt_char_attrs[x] = line->vt_char_attrs[x] ;
                }
            }
        }
#ifdef KUI
#ifdef PACKED_CELL_ATTRS
        if (ISDECTERM(tt_type_mode) || ISK95(tt_type_mode)) {
            /* Preserve ruled lines too. The DECterm documentation for ruled
             * lines doesn't say anything about DECSED, but it does seem to at
             * least *try* to preserve them. It seems to be buggy though - some
             * ruled lines survive, but not all. */
            memcpy(newline->cell_attrs, line->cell_attrs,
                    sizeof(vt_cell_attr_t) * CELL_ATTR_LEN);
        }
#endif /* PACKED_CELL_ATTRS */
#endif /* KUI */
    }
}


void
selclrtoeoln( BYTE vmode, CHAR fillchar ) {  /* | Page: Cursor */
    int x ;
    videoline * line = NULL ;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* take care of current line */
    line = VscrnGetLineFromTop( vmode, wherey[vmode]-1, FALSE ) ;
    for ( x=wherex[vmode]-1 ; x < MAXTERMCOL ; x++ ) {
        if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) ) {
            line->cells[x].c = fillchar ;
            /* DEC STD 070 says: "The character rendition and attributes
             * associated with each position do not change". I don't know if
             * other emulations using this function behave the same way or not,
             * so for now they get the prior behaviour of erasing everything */
            if (!ISVT220(tt_type_mode))
            {
                line->cells[x].video_attr = cellcolor;
                line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
            }
        }
    }
}

void
selclreoscr_escape( BYTE vmode, CHAR fillchar ) {  /* | Page: Cursor */
    int x,y;
    videoline * line = NULL;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    if (wherex[vmode] == 1 && wherey[vmode] == 1) {
        selclrscreen(vmode, fillchar);
        return;
    }

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=wherex[vmode]-1 ; x <MAXTERMCOL ; x++ )
        {
        if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) ) {
            line->cells[x].c = fillchar ;

            /* DEC STD 070 says: "The character rendition and attributes
             * associated with each position do not change". I don't know if
             * other emulations using this function behave the same way or not,
             * so for now they get the prior behaviour of erasing everything */
            if (!ISVT220(tt_type_mode))
            {
                line->cells[x].video_attr = cellcolor;
                line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
            }
        }
    }

    /* now take care of additional lines */
    for ( y=wherey[vmode] ; y<VscrnGetHeight(vmode)-(tt_status[vmode]?1:0) ; y++ ) {
        line = VscrnGetLineFromTop(vmode, y, FALSE) ;
        for ( x=0 ; x <MAXTERMCOL ; x++ ) {
            if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) ) {
                line->cells[x].c = fillchar ;
                /* See DEC STD 070 comment above */
                if (!ISVT220(tt_type_mode))
                {
                    line->cells[x].video_attr = cellcolor;
                    line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
                }
            }
        }
    }
}

void
selclrboscr_escape( BYTE vmode, CHAR fillchar ) {  /* | Page: Cursor */
    int x,y;
    videoline * line = NULL;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* now take care of first wherey[vmode]-1 lines */
    for ( y=0 ; y<wherey[vmode]-1 ; y++ ) {
        line = VscrnGetLineFromTop(vmode, y, FALSE) ;
        for ( x=0 ; x <MAXTERMCOL ; x++ ) {
            if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) ) {
                line->cells[x].c = fillchar ;
                /* DEC STD 070 says: "The character rendition and attributes
                 * associated with each position do not change". I don't know if
                 * other emulations using this function behave the same way or not,
                 * so for now they get the prior behaviour of erasing everything */
                if (!ISVT220(tt_type_mode)) {
                    line->cells[x].video_attr = cellcolor;
                    line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
                }
            }
        }
    }

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=0 ; x < wherex[vmode] ; x++ ) {
        if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) ) {
            line->cells[x].c = fillchar ;
            /* See DEC STD 070 comment above */
            if (!ISVT220(tt_type_mode)) {
                line->cells[x].video_attr = cellcolor;
                line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
            }
        }
    }
}

void
selclrbol_escape( BYTE vmode, CHAR fillchar ) { /* | Page: Cursor */
    videoline * line = NULL ;
    int x ;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=0 ; x < wherex[vmode] ; x++ )
        {
        if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) ) {
            line->cells[x].c = fillchar ;
            /* DEC STD 070 says: "The character rendition and attributes
             * associated with each position do not change". I don't know if
             * other emulations using this function behave the same way or not,
             * so for now they get the prior behaviour of erasing everything */
            if (!ISVT220(tt_type_mode))
            {
                line->cells[x].video_attr = cellcolor;
                line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
            }
        }
    }
}

void
selclrline_escape( BYTE vmode, CHAR fillchar ) { /* | Page: Cursor */
    videoline * line = NULL ;
    int x ;
    cell_video_attr_t cellcolor = geterasecolor(vmode);

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* take care of current line */
    line = VscrnGetLineFromTop(vmode, wherey[vmode]-1, FALSE) ;
    for ( x=0 ; x < MAXTERMCOL ; x++ ) {
        if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED ) ) {
            line->cells[x].c = fillchar ;
            /* DEC STD 070 says: "The character rendition and attributes
             * associated with each position do not change". I don't know if
             * other emulations using this function behave the same way or not,
             * so for now they get the prior behaviour of erasing everything */
            if (!ISVT220(tt_type_mode))
            {
                line->cells[x].video_attr = cellcolor;
                line->vt_char_attrs[x] = VT_CHAR_ATTR_ERASED ;
            }
        }
    }
}


void
selclrcol_escape( BYTE vmode, CHAR fillchar ) {
    int ys = VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0);
    int x  = wherex[VTERM]-1 ;
    int y ;
    vtattrib vta ={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    viocell cell;

    cell.c = fillchar;
    cell.video_attr = geterasecolor(vmode);
    /* TODO: vta.erased = TRUE; ?
     * Used by WYSE emulations to selectively clear a column to a particular
     * character, so perhaps not? */

    if ( fillchar == NUL )
        cell.c = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    for ( y=0 ; y<ys ; y++ ) {
        if ( !VscrnGetVtCharAttr(VTERM,x,y).unerasable )
            VscrnWrtCell( VTERM, cell, vta, y, x ) ;
    }
}

/* Clears a rectangle from current cursor position to row,col */
/* using fillchar.                                            */
void
selclrrect_escape( BYTE vmode, int top, int left, int bot, int right,
                   CHAR fillchar )
{
    int startx, starty, endx, endy, l, x ;
    videoline * line = NULL ;
    cell_video_attr_t cellcolor = geterasecolor(vmode) ;

    if ( left < right ) {
        startx = left - 1 ;
        endx   = right - 1 ;
    }
    else {
        startx = right - 1 ;
        endx = left - 1 ;
    }

    if ( top < bot ) {
        starty = top - 1 ;
        endy   = bot - 1 ;
    }
    else {
        starty = bot - 1 ;
        endy = top - 1 ;
    }

    if ( fillchar == NUL )
        fillchar = SP ;
    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    /* check to see if any of the lines are protected */
    /* if so, abort                                   */

    for ( l=starty ; l <= endy ; l++ )
        if ( VscrnGetLineFromTop( vmode, l, FALSE )->vt_line_attr & WY_LINE_ATTR_PROTECTED )
            return ;

    /* so now we just need to clear each row */

    for ( l=starty ; l <= endy ; l++ ) {
        line = VscrnGetLineFromTop( vmode, l, FALSE ) ;
        for ( x=startx ; x <= endx ; x++ )
        {
            if ( !(line->vt_char_attrs[x] & VT_CHAR_ATTR_PROTECTED) &&
                 line->vt_char_attrs[x] != VT_CHAR_ATTR_ERASED ) {
                line->cells[x].c = fillchar ;

                /* From the VT525 manual:
                 *   DECSERA does not change:
                 *      - Visual attributes set by the select graphic rendition
                 *        (SGR) function
                 *      - Protection attributes set by DECSCA
                 *      - Line attributes
                 * I'm unsure if the wyse emulation that also uses this function
                 * also behaves the same way, so for now it gets the prior
                 * behaviour
                 */
                if (!ISVT420(tt_type_mode))
                {
                    line->cells[x].video_attr = cellcolor;
                    line->vt_char_attrs[x] = VT_CHAR_ATTR_NORMAL ;
                }
            }
        }
    }
}

/* Draws a box from current cursor to row,col */
void
boxrect_escape( BYTE vmode, int row, int col )
{
    int brow, bcol, erow, ecol, x, y ;
    viocell cell ;
    vtattrib vta = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};

    if ( vmode == VTERM ) {
        cell.video_attr = attribute ;
        vta = attrib ;
    }
    else
        cell.video_attr = colorcmd ;

    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    if ( wherey[vmode] < row ) {
        brow = wherey[vmode] ;
        erow = row ;
    }
    else {
        brow = row ;
        erow = wherey[vmode] ;
    }

    if ( wherex[vmode] < col ) {
        bcol = wherex[vmode] ;
        ecol = col ;
    }
    else {
        bcol = col ;
        ecol = wherex[vmode] ;
    }

    cell.c = '|' ;
    for ( y = brow ; y <= erow ; y++ ) {
        VscrnWrtCell( vmode, cell, vta, y, bcol ) ;
    }
    for ( y = brow ; y <= erow ; y++ ) {
        VscrnWrtCell( vmode, cell, vta, y, ecol ) ;
    }
    cell.c = '-' ;
    for ( x = bcol ; x <= ecol ; x++ ) {
        VscrnWrtCell( vmode, cell, vta, brow, x ) ;
    }
    for ( x = bcol ; x <= ecol ; x++ ) {
        VscrnWrtCell( vmode, cell, vta, erow, x ) ;
    }
}

#ifdef KUI
#define DECDRLBR_BOTTOM  0x01
#define DECDRLBR_RIGHT   0x02
#define DECDRLBR_TOP     0x04
#define DECDRLBR_LEFT    0x08
void
ruledlines_escape(int pattern, int left, int top, int width, int height, BOOL set) {
	int right, bot, x, y;

    if (pattern & 0x0F == 0) return; /* Nothing to do */

	/* Columns and lines are numbered from 0 */
    left -= 1;
    right = left + width-1;
    bot = top + height-1;

    /* Top or Bottom boundary */
    if (pattern & DECDRLBR_BOTTOM || pattern & DECDRLBR_TOP) {
        videoline *topLine = NULL;
        videoline *botLine = NULL;

        /* Top line */
        if (pattern & DECDRLBR_TOP) {
            debug(F111, "Ruled Lines top at", "y", top - 1);
            topLine = VscrnGetLineFromTop(vmode, top - 1, FALSE);
        }

        if (pattern & DECDRLBR_BOTTOM) {
            debug(F111, "Ruled Lines bot at", "y", bot - 1);
            botLine = VscrnGetLineFromTop(vmode, bot - 1, FALSE);
        }

        /* Cells are numbered from 0 */
        for (x = left; x <= right; x++) {
            if (topLine) {
                debug(F111, "Ruled Lines top at", "x", x);
                CELL_ATTR_SET(topLine,x,
					set ? CELL_ATTR_GET(topLine,x) | CA_ATTR_TOP_BORDER
                    	: CELL_ATTR_GET(topLine,x) & ~CA_ATTR_TOP_BORDER);
            }

            if (botLine) {
                debug(F111, "Ruled Lines bot at", "x", x);
                 CELL_ATTR_SET(botLine,x,
                    set ? CELL_ATTR_GET(botLine,x) | CA_ATTR_BOTTOM_BORDER
						: CELL_ATTR_GET(botLine,x) & ~CA_ATTR_BOTTOM_BORDER);
            }
        }
    }

    /* Left or Right boundary */
    if (pattern & DECDRLBR_RIGHT || pattern & DECDRLBR_LEFT) {
        debug(F111, "Ruled Lines left at", "x", left);
        debug(F111, "Ruled Lines left at", "x", right);
        for (y = top-1; y < bot; y++) {
            videoline *line = VscrnGetLineFromTop(vmode, y, FALSE);

            if (pattern & DECDRLBR_LEFT) {
                debug(F111, "Ruled Lines left at", "y", y);
                CELL_ATTR_SET(line,left,
					set ? CELL_ATTR_GET(line,left) | CA_ATTR_LEFT_BORDER
                    	: CELL_ATTR_GET(line,left) & ~CA_ATTR_LEFT_BORDER);
            }

            if (pattern & DECDRLBR_RIGHT) {
                debug(F111, "Ruled Lines right at", "y", y);
                CELL_ATTR_SET(line,right,
					set ? CELL_ATTR_GET(line,right) | CA_ATTR_RIGHT_BORDER
                    	: CELL_ATTR_GET(line,right) & ~CA_ATTR_RIGHT_BORDER);
            }
        }
    }

    if (cursor_on_visible_page(VTERM)) {
    	VscrnIsDirty(vmode);
	}
}

/* Erase all ruled lines in an area */
void
decerlbra_escape(int left, int top, int width, int height) {
	int right, bot, x, y, mask;

	/* Columns and lines are numbered from 0 */
    left -= 1;
    right = left + width-1;
    bot = top + height-1;

	mask = ~(CA_ATTR_TOP_BORDER | CA_ATTR_BOTTOM_BORDER |
				CA_ATTR_LEFT_BORDER | CA_ATTR_RIGHT_BORDER);

	for (y = top-1; y < bot; y++) {
		videoline *line = VscrnGetLineFromTop(vmode, y, FALSE);

        for (x = left; x <= right; x++) {
            CELL_ATTR_SET(line,x, CELL_ATTR_GET(line,x) & mask);
        }
	}

	if (cursor_on_visible_page(VTERM)) {
    	VscrnIsDirty(vmode);
	}
}

#endif /* KUI */

void
decdwl_escape(bool dwlflag) {
    videoline * line = NULL ;
    viocell       * cells = NULL ;

    /* DECDWL */
    line = VscrnGetLineFromTop(VTERM, wherey[VTERM]-1, FALSE) ;
    cells = line->cells ;

     if ( dwlflag != line->vt_line_attr ) {
         /* change size */
       line->vt_line_attr = dwlflag ;
    }
}

/*----------------------------------------------------------+----------------*/
/* calculate_decrqcra_checksum                              | Page: specified*/
/*----------------------------------------------------------+----------------*/
/* This algorithm matches what the VT520 does, and *should* also be correct for
 * the VT525 when using its colour palette. It is invoked by either the DECRQCRA
 * control sequence, or the \fterminalchecksum function. */
int
calculate_decrqcra_checksum(int top, int left, int bot, int right, int page,
                            BOOL obey_margins) {
    unsigned short checksum=0;
    int x, y, height, width, max_page;
    char include_color;

    /* Only include colour information specifically for these terminal types. We
     * cant use ISVT525() at the moment because thats currently returning true
     * for the VT320, etc, in order to make VT525 features available in the
     * absence of a real VT525 emulation. So instead K95 and XTERM will behave
     * as the VT525 does, while VT320 will behave as the VT420 does. When a
     * proper VT525 emulation is added this should be updated. */
    include_color = tt_type_mode == TT_VT525 || ISK95(tt_type_mode)
        || ISXTERM(tt_type_mode);

    height = VscrnGetHeight(VTERM) - (tt_status[VTERM] ? 1 : 0);
    width = VscrnGetWidth(VTERM);
    max_page = term_max_page(VTERM);

    if (top < 1) top = 1;
    if (left < 1) left = 1;
    if (bot < 1) bot = height;
    if (right < 1) right = width;

    /* If page is zero, then do all pages. Otherwise do the specified page */
    if (page < 1) {
        page = 0;
        top = 1;
        left = 1;
        bot = height;
        right = width;
    } else {
        page = page - 1;
        if (page > max_page) page = max_page;
        max_page = page;
    }

    if (obey_margins) {
        debug(F111, "DECRQCRA", "margintop", vscrn_page_margin_top(VTERM,page));
        debug(F111, "DECRQCRA", "marginleft", vscrn_page_margin_left(VTERM,page));
        debug(F111, "DECRQCRA", "marginbot", vscrn_page_margin_bot(VTERM,page));
        debug(F111, "DECRQCRA", "marginright", vscrn_page_margin_right(VTERM,page));

        top += vscrn_page_margin_top(VTERM,page) - 1;
        bot += vscrn_page_margin_top(VTERM,page) - 1;
        left += vscrn_page_margin_left(VTERM,page) - 1;
        right += vscrn_page_margin_left(VTERM,page) - 1;

        if (bot > vscrn_page_margin_bot(VTERM,page)) bot = vscrn_page_margin_bot(VTERM,page);
        if (right > vscrn_page_margin_right(VTERM,page)) right = vscrn_page_margin_right(VTERM,page);
    } else {
        if (bot > height) bot = height;
        if (top > bot) top = 1;
        if (right > width) right = width;
        if (left > right) left = 1;
    }

    debug(F111, "DECRQCRA", "top", top);
    debug(F111, "DECRQCRA", "left", left);
    debug(F111, "DECRQCRA", "bot", bot);
    debug(F111, "DECRQCRA", "right", right);

    for (; page <= max_page; page++) {
        debug(F111, "DECRQCRA", "page", page);
        for ( y=top-1; y<bot; y++ ) {
            videoline * line = VscrnGetPageLineFromTop(VTERM, y, page);
            for ( x=left-1; x<right; x++ ) {
                unsigned short c, a;
                unsigned char fgcoloridx = 0, bgcoloridx = 0;

                c = line->cells[x].c;
                a = line->vt_char_attrs[x];

                /* TODO: If c is outside the range of values for the latin1
                 *       character set, the calculation here will be incorrect
                 *       as the values the VT420/VT520 assigns to those
                 *       characters unsurprisingly differ from Unicode. For the
                 *       calculation to match the real terminal we'll need to do
                 *       Unicode->VT conversion here. */

                if (a == VT_CHAR_ATTR_ERASED) {
                    /* Unoccupied character cells are excluded from the checksum */
                    continue;
                }

                if (include_color) {
                    /* These will be 0 for RGB colours */
                    fgcoloridx = cell_video_attr_foreground(line->cells[x].video_attr);
                    bgcoloridx = cell_video_attr_background(line->cells[x].video_attr);

#ifdef CK_COLORS_24BIT
                    /* If the currently assigned foreground or background colour is is a
                     * direct 24-bit RGB colour, then use the nearest colour in the
                     * VT525 or 16-colour palette for the checksum. */
                    if (!cell_video_attr_fg_is_indexed(line->cells[x].video_attr)) {
                        int r, g, b;
                        r = cell_video_attr_fg_rgb_r(line->cells[x].video_attr);
                        g = cell_video_attr_fg_rgb_g(line->cells[x].video_attr);
                        b = cell_video_attr_fg_rgb_b(line->cells[x].video_attr);

                        /* If we're emulating a VT525 we'll use its palette as the
                         * target - not that we should ever be doing RGB colour in
                         * a VT525 emulation */
                        fgcoloridx = nearest_palette_color_rgb(
                            ISVT525(tt_type_mode) ? CK_PALETTE_VT525 : CK_PALETTE_16,
                            r, g, b);
                    }
                    if (!cell_video_attr_bg_is_indexed(line->cells[x].video_attr)) {
                        int r, g, b;
                        r = cell_video_attr_bg_rgb_r(line->cells[x].video_attr);
                        g = cell_video_attr_bg_rgb_g(line->cells[x].video_attr);
                        b = cell_video_attr_bg_rgb_b(line->cells[x].video_attr);

                        bgcoloridx = nearest_palette_color_rgb(
                            ISVT525(tt_type_mode) ? CK_PALETTE_VT525 : CK_PALETTE_16,
                            r, g, b);
                    }
#endif /* CK_COLORS_24BIT */

                    /* If the colour is outside the valid range for a VT525, convert it
                     * to the VT525 palette. We'll leave the regular SGR colours as-is.
                     */
                    if (fgcoloridx > palette_max_index(CK_PALETTE_VT525)) {
                        fgcoloridx = nearest_palette_color_palette(colorpalette,
                            fgcoloridx);
                    }

                    if (bgcoloridx > palette_max_index(CK_PALETTE_VT525)) {
                        bgcoloridx = nearest_palette_color_palette(colorpalette,
                            bgcoloridx);
                    }

                    /* The lower 16 colours in the vscreen buffer are arranged a
                     * little different from SGR colours for OS/2 reasons - this
                     * will fix that up */
                    fgcoloridx = color_index_from_vio(fgcoloridx);
                    bgcoloridx = color_index_from_vio(bgcoloridx);
                }

                checksum -= c;

                /* The VT420, VT520 and VT525 only support these attributes */
                if (a & VT_CHAR_ATTR_PROTECTED) checksum -= 0x04;
                if (a & VT_CHAR_ATTR_INVISIBLE) checksum -= 0x08;
                if (a & VT_CHAR_ATTR_UNDERLINE) checksum -= 0x10;
                if (a & VT_CHAR_ATTR_REVERSE) checksum -= 0x20;
                if (a & VT_CHAR_ATTR_BLINK) checksum -= 0x40;
                if (a & VT_CHAR_ATTR_BOLD) checksum -= 0x80;
                if (include_color) {
                    checksum -= (unsigned short)fgcoloridx << 4;
                    checksum -= bgcoloridx;
                }
            }
        }
    }
    debug(F111, "DECRQCRA", "checksum", checksum);
    return checksum;
}


/*----------------------------------------------------------+----------------*/
/* sgr_38_48                                                | Page: n/a      */
/*----------------------------------------------------------+----------------*/
/* Implements SGR-38 and SGR-48 returning the result. If no parameter elements
 * are encountered, it will fall back to assuming the old non-compliant
 * semicolon format advancing j (the pointer to the current pn) as necessary.
 * If allow_malformed_sequence is false, it will return the original attribute
 * without modification for the non-compliant semicolon format but j will still
 * be advanced.
 *
 * Parameters:
 *  pn[]    - CSI parameters
 *  pe[]    - Parameter elements for pn[*j]
 *  k       - Number of parameters supplied in pn[]
 *  *pn_pos - Position of this invocation of SGR-38 or SGR-48 in pn[]
 *  pn_pe_start[] - Position of first value in pe[], or -1 if pe[] is empty
 *  pn_pe_count[] - Number of values in pe[]
 *  allow_malformed_sequence - If false, return original attribute for
 *              non-compliant semicolon format while still advancing *j
 *  attribute - initial value of cell video attribute to possibly modify
 *
 *  Returns:
 *      attribute, potentially modified as a result of processing an SGR-38 or
 *      SGR-48 control sequence.
 */
static cell_video_attr_t
sgr_38_48(int pn[], int pe[], int k, unsigned short *pn_pos, int pn_pe_start[],
    int pn_pe_count[], bool allow_manformed_sequence,
    cell_video_attr_t attribute) {

    int mode=0, index=0, r=0, g=0, b=0;
    unsigned short j = *pn_pos;
	int fg = (pn[j] == 38);

	debug(F111, "SGR 38/48", "SGR", pn[j]);

    if ( !sgrcolors )
        return attribute;

	if (pn_pe_start[j] == -1) {
		int i, pn_rem = 0;
		debug(F111, "SGR 38/48: Using semicolons", "pn_pe_start[j]", pn_pe_start[j]);

		mode = pn[j+1];
		pn_rem = k - j;   /* for (j = 1; j <= k; ++j) */

		if (mode == 2 && pn_rem >= 3) {
			j+=2; /* SGR 38/48 + mode */
			r = pn[j]; j++;
			g = pn[j]; j++;
			b = pn[j];
		} else if (mode == 5 && pn_rem >= 1) {
			j+=2; /* mode */
			index = pn[j];
		}

	    if (!allow_manformed_sequence) {
	        debug(F100, "Rejecting malformed SGR-38/-48 sequence using semicolons instead of parameter elements", 0, 0);
	        *pn_pos = j;
	        return attribute;
	    }

		debug(F111, "SGR 38/48: Using semicolons", "j", j);
		debug(F111, "SGR 38/48: Using semicolons", "k", k);
	} else {
		int st = pn_pe_start[j];
		int c = pn_pe_count[j];
		debug(F111, "SGR 38/48: Using parameter elements", "pn_pe_start[j]", st);
		debug(F111, "SGR 38/48: Using parameter elements", "pn_pe_count[j]", c);

		if (c == 4 && pe[st] == 2) {
			mode = pe[st];
			r = pe[st+1];
			g = pe[st+2];
			b = pe[st+3];
		} else if (c == 5 && pe[st] == 2) {
			mode = pe[st];
			/* colorspace = pe[st+1];  Not used */
			r = pe[st+2];
			g = pe[st+3];
			b = pe[st+4];
		} else if (c == 2 && pe[st] == 5) {
			mode = pe[st];
			index = pe[st+1];
		} else {
			debug(F111, "SGR 38/48 - ERROR - insufficient or invalid mode", "pe-count", c);
			debug(F111, "SGR 38/48 - ERROR - insufficient or invalid mode", "pe-start", st);
			debug(F111, "SGR 38/48 - ERROR - insufficient or invalid mode", "mode", pe[st]);
		}
	}

    debug(F111, "SGR 38/48:", "mode", mode);

	if (mode == 5) {
		int max_colors = current_palette_max_index();
        /* K95s color IDs for colors 1-15 are different
		 * from those used by xterm due to its OS/2
		 * origins.
		 */
        index = color_index_to_vio(index);

		debug(F111, "SGR 38/48:", "index", index);

        if (index <= max_colors) {
			debug(F111, "SGR 38/48: set indexed color", "index", index);
#ifdef CK_COLORS_16
            /* For 16-color builds, map from the currently
			 * set palette on to the aixterm-16 palette.
             */
            index = nearest_palette_color_palette(colorpalette, index);
#endif /* CK_COLORS_16 */
			if (fg) attribute = cell_video_attr_set_fg_color(attribute,index);
			else	attribute = cell_video_attr_set_bg_color(attribute,index);
        }
	}
	/* Direct (24-bit) color value? */
	else if (mode == 2) {
		debug(F111, "SGR 38/48: set RGB color", "r", r);
		debug(F111, "SGR 38/48: set RGB color", "g", g);
		debug(F111, "SGR 38/48: set RGB color", "b", b);
#ifdef CK_COLORS_24BIT
		if (colorpalette == CK_PALETTE_XTRGB || colorpalette == CK_PALETTE_XTRGB88) {
			if (fg) attribute = cell_video_attr_set_fg_rgb(attribute, r, g, b);
			else    attribute = cell_video_attr_set_bg_rgb(attribute, r, g, b);
        } else
#endif /* CK_COLORS_24BIT */
		{
			int idx;
			/* Can't store 24-bit color, so look for the nearest
			 * color in the current palette and use that.*/
			idx = nearest_palette_color_rgb(colorpalette, r, g, b);
			if (fg) attribute = cell_video_attr_set_fg_color(attribute,idx);
			else    attribute = cell_video_attr_set_bg_color(attribute,idx);
		}
	} else {
		debug(F111, "SGR 38/48 - ERROR - invalid mode", "mode", mode);
	}

    *pn_pos = j;
    return attribute;
}

/*----------------------------------------------------------+----------------*/
/* change_attributes_in_rectangle (DECCARA)                 | Page: cursor   */
/*----------------------------------------------------------+----------------*/
static vt_char_attr_t
deccara_attribute(vt_char_attr_t a, int pn) {
    switch ( pn ) {
        case 0:
            a = VT_CHAR_ATTR_NORMAL;
            break;
        case 1:
            a |= VT_CHAR_ATTR_BOLD;
            break;
        case 4:
            a |= VT_CHAR_ATTR_UNDERLINE;
            break;
        case 5:
            a |= VT_CHAR_ATTR_BLINK;
            break;
        case 7:
            a |= VT_CHAR_ATTR_REVERSE;
            break;
        case 22:
            a &= ~VT_CHAR_ATTR_BOLD;
            break;
        case 24:
            a &= ~VT_CHAR_ATTR_UNDERLINE;
            break;
        case 25:
            a &= ~VT_CHAR_ATTR_BLINK;
            break;
        case 27:
            a &= ~VT_CHAR_ATTR_REVERSE;
            break;
    }
    return a;
}

static cell_video_attr_t
deccara_video_attribute(cell_video_attr_t a, int pn) {
    int fg = -1, bg = -1;
    switch ( pn ) {
    case 30: /* Colors */
    case 31:
    case 32:
    case 33:
    case 34:
    case 35:
    case 36:
    case 37:
        /* Select foreground color */
        if ( !sgrcolors )
            break;
        fg = sgrcols[pn - 30];
        break;
    case 40:
    case 41:
    case 42:
    case 43:
    case 44:
    case 45:
    case 46:
    case 47:
        /* Select background color */
        if ( !sgrcolors )
            break;
        bg = sgrcols[pn - 40];
        break;
    case 90: /* Colors */
    case 91:
    case 92:
    case 93:
    case 94:
    case 95:
    case 96:
    case 97:
        /* Select foreground color (8-bit high) */
        if ( !sgrcolors || !ISK95(tt_type_mode) )
            break;
        fg = sgrcols[pn - 90] + 8;
        break;
    case 100:
    case 101:
    case 102:
    case 103:
    case 104:
    case 105:
    case 106:
    case 107:
        /* Select background color (8-bit high) */
        if ( !sgrcolors || !ISK95(tt_type_mode) )
            break;
        bg = sgrcols[pn - 100] + 8;
        break;
    default:
        return a;
    }

    if ((fg >= 0 || bg >= 0)) {
        if (fg >= 0)
            a = cell_video_attr_set_fg_color(a, fg);
        if (bg >= 0)
            a = cell_video_attr_set_bg_color(a, bg);
    }
    return a;
}

/* Parameters:
 *  vmode   - should be VTERM
 *  pn[]    - Array of CSI parameters
 *  k       - Count of CSI parameters
 *  *j      - Current position in the CSI parameters. May be advanced if
 *            SGR-38 or SGR-48 is encountered
 *  pe[]    - CSI parameter elements
 *  pn_pe_start[] - first Pe for each Pn
 *  pn_pe_count[] - Number of Pe for each Pn
 */
static void
change_attributes_in_rectangle(int vmode, int pn[], int k, unsigned short* j,
    int pe[], int pn_pe_start[], int pn_pe_count[]) {
    int w, h, x, y;
    unsigned short z;
    /*
     * pn[1] - top-line border      default=1
     * pn[2] - left-col border      default=1
     * pn[3] - bottom-line border   default=last line
     * pn[4] - right col border     default=last column
     * pn[5] -> pn[k] attributes to change - default=0
     *
     *  0 - attributes off
     *  1 - bold
     *  4 - underline
     *  5 - blink
     *  7 - negative image
     * 22 - no bold
     * 24 - no underline
     * 25 - no blink
     * 27 - positive image
     * 30..38 - foreground color
     * 40..48 - background color
     * 90..97 - bright foreground color
     * 100..107 - bright background color
     *
     * decsace == FALSE, stream else rectangle
     */
    if ( k < 1 || pn[1] == 0 ) pn[1] = 1;
    if ( k < 2 || pn[2] == 0 ) pn[2] = 1;
    if ( k < 3 || pn[3] == 0 ) pn[3] = VscrnGetHeight(vmode)
         -(tt_status[vmode]?1:0);
    if ( k < 4 || pn[4] == 0 ) pn[4] = VscrnGetWidth(vmode);
    if ( k < 5 ) {
        pn[5] = 0;
        k = 5;
    }

    if (relcursor) {
        /* Add top and left margins to the vertical and
         * horizontal coordinates */
        pn[1] += vscrn_c_page_margin_top(vmode)-1; /* top */
        pn[2] += vscrn_c_page_margin_left(vmode)-1;/* lft */
        pn[3] += vscrn_c_page_margin_top(vmode)-1; /* bot */
        pn[4] += vscrn_c_page_margin_left(vmode)-1;/* rt */

        if (pn[3] > vscrn_c_page_margin_bot(vmode))
            pn[3] = vscrn_c_page_margin_bot(vmode);
        if (pn[4] > vscrn_c_page_margin_right(vmode))
            pn[4] = vscrn_c_page_margin_right(vmode);
    }

    if ( pn[3] < pn[1] || pn[4] < pn[2] )
        return;

    w = pn[4] - pn[2] + 1;
    h = pn[3] - pn[1] + 1;

    if ( decsace ) {        /* rectangle */
        for ( y=0; y<h; y++ ) {
            videoline * line = VscrnGetLineFromTop(vmode, pn[1]+y-1, FALSE);
            for ( x=0; x<w; x++ ) {
                for ( z=5; z<=k; z++ ) {
                    vt_char_attr_t a = line->vt_char_attrs[pn[2]+x-1];
                    if (a == VT_CHAR_ATTR_ERASED) {
                        /* In rectangle mode, unoccuped (erased)
                         * character positions are changed to
                         * blanks (become unerased) */
                        a = VT_CHAR_ATTR_NORMAL;
                    }
                    line->vt_char_attrs[pn[2]+x-1] = deccara_attribute(a, pn[z]);

                    /* Changing colours with DECCARA is an extension which
                     * STD-070 implies should be supported by the VT525:
                     * https://j4james.github.io/vtdocs/EL-00070-05.html#5-174
                     * So for now the VT525 is assumed to support it.
                     */
                    if (ISK95(tt_type_mode) || ISVT525(tt_type_mode)) {
                        cell_video_attr_t attr = line->cells[pn[2]+x-1].video_attr;
                        if (pn[z] == 0 && colorreset) {
                            attr = defaultattribute;
                        }
                        else if ((pn[z] == 38 || pn[z] == 48) && ISK95(tt_type_mode)) {
                            /* Handle indexed or RGB colour. We explicitly do
                             * not support the semi-colon based syntax because:
                             *  - It breaks the standard
                             *  - The user has no reason to expect it to work here
                             * We *only* support that broken semicolon syntax in
                             * SGR because its already so widespread there. So
                             * if a user tries to use it here we'll detect it
                             * and skip over the next few Pn anyway. */
                            attr = sgr_38_48(pn, pe, k, &z, pn_pe_start,
                                pn_pe_count, FALSE, attr);
                        }
                        else {
                            /* Handle 30..37, 40..47, 90..97 and 100..107 */
                            attr = deccara_video_attribute(attr, pn[z]);
                        }
                        line->cells[pn[2]+x-1].video_attr = attr;
                    }
                }
            }
        }
    } else {                /* stream */
        for ( y=0; y<h; y++ ) {
            videoline * line = VscrnGetLineFromTop(vmode, pn[1]+y-1, FALSE);
            int rlimit = relcursor ? vscrn_c_page_margin_right(vmode) : VscrnGetWidth(vmode);
            int llimit = relcursor ? vscrn_c_page_margin_left(vmode)-1 : 0;
            for ( x = (y==0 ? pn[2] - 1 : llimit);
                  x < ((y==h-1) ? pn[4] : rlimit);
                  x++ ) {
                if (line->vt_char_attrs[x] == VT_CHAR_ATTR_ERASED) {
                    /* In stream mode, DECCARA doesn't affect
                     * unoccupied (erased) character positions */
                    continue;
                }
                for ( z=5; z<=k; z++ ) {
                    vt_char_attr_t a = line->vt_char_attrs[x];
                    line->vt_char_attrs[x] = deccara_attribute(a, pn[z]);

                    if (ISK95(tt_type_mode) || ISVT525(tt_type_mode)) {
                        cell_video_attr_t attr = line->cells[x].video_attr;
                        if (pn[z] == 0 && colorreset) {
                            attr = defaultattribute;
                        }
                        else if ((pn[z] == 38 || pn[z] == 48) && ISK95(tt_type_mode)) {
                            /* Handle indexed or RGB colour. We explicitly do
                             * not support the semi-colon based syntax because:
                             *  - It breaks the standard
                             *  - The user has no reason to expect it to work here
                             * We *only* support that broken semicolon syntax in
                             * SGR because its already so widespread there. So
                             * if a user tries to use it here we'll detect it
                             * and skip over the next few Pn anyway. */
                            attr = sgr_38_48(pn, pe, k, &z, pn_pe_start,
                                pn_pe_count, FALSE, attr);
                        }
                        else {
                            /* Handle 30..37, 40..47, 90..97 and 100..107 */
                            attr = deccara_video_attribute(attr, pn[z]);
                        }
                        line->cells[x].video_attr = attr;
                    }
                }
            }
        }
    }
    if (cursor_on_visible_page(vmode)) {
        VscrnIsDirty(vmode);
    }
}


/*----------------------------------------------------------+----------------*/
/* TODO: terminal_state_report                              | Page: n/a      */
/*----------------------------------------------------------+----------------*/
void
terminal_state_report() {
    /* The format of this is apparently intentionally undocumented and can vary
     * between terminal models and even firmware versions. Response is
     * sixel-encoded 8-bit bytes. Total length of the response (from DCS to
     * terminating ST) is guaranteed to not exceed 256 characters.
     *
     * As there is no defined format for the response, K95 is free to define
     * something with no need for it to be portable to other terminals or
     * terminal emulators. The only question is... what to include? */
}

/*----------------------------------------------------------+----------------*/
/* presentation_state_report                                | Page: n/a      */
/*----------------------------------------------------------+----------------*/
/* Produces one of two Presentation State Reports:
 *      1       Cursor Information Report
 *      2       Tabstop Report
 */
void
presentation_state_report(int report) {  /* DECRQPSR */
    char response[100];
    char* decrqpsr = NULL;

    response[0] = '\0';

    switch (report) {
    case 1: {   /* DECCIR - Cursor Information Report */
        char srend, satt, sflag, scss, pgl, pgr;

        /* Response is:
         *   Pr ; Pc ; Pp ; Srend ; Satt ; Sflag ; Pg1 ; Pgr ; Scss ; Sdesig
         * Where:
         *   Pr,Pc  Cursor position (eg, 5;20)
         *   Pp     Current page number (eg, 3)
         *   Srend  Bit field of graphic renditions
         *
         * My VT520 in power on state gives:
         * 1;1;1;@;@;@;0;2;@;BB<<
         */

        srend = '@';  /* @ is 01000000 */
        /* bit 8 - always reset */
        /* bit 7 - always set */
        /* bit 6 - extension indicator, signals another byte */
        if (attrib.invisible) srend += 16;      /* bit 5 */
        if (attrib.reversed) srend += 8;        /* bit 4 */
        if (attrib.blinking) srend += 4;        /* bit 3 */
        if (attrib.underlined) srend += 2;      /* bit 2 */
        if (attrib.bold) srend += 1;            /* bit 1 */

        satt = '@';  /* @ is 01000000 */
        /* bit 8 - always reset */
        /* bit 7 - always set */
        /* bit 6 - extension indicator, signals another byte */
        /* bits 5, 4, 3, 2 - reserved for future use */
        /* bit 1 - selectively erasable attribute */
        if (attrib.unerasable) satt += 1;  /* bit 1 */

        sflag = '@';  /* @ is 01000000 */
        /* bit 8 - always reset */
        /* bit 7 - always set */
        /* bit 6 - extension indicator, signals another byte */
        /* bit 5 - reserved */
        if (wrapit) sflag += 8; /* bit 4 - autowrap pending */
        /* bit 3 - SS3 pending */
        if (SSGL != NULL && SSGL == &G[3]) sflag += 4;
        /* bit 2 - SS2 pending */
        if (SSGL != NULL && SSGL == &G[2]) sflag += 2;
        if (relcursor) sflag += 1; /* bit 1 - origin mode */

        if (GL == &G[0]) pgl = '0';
        else if (GL == &G[1]) pgl = '1';
        else if (GL == &G[2]) pgl = '2';
        else if (GL == &G[3]) pgl = '3';

        if (GR == &G[0]) pgr = '0';
        else if (GR == &G[1]) pgr = '1';
        else if (GR == &G[2]) pgr = '2';
        else if (GR == &G[3]) pgr = '3';

        scss = '@';  /* @ is 01000000 */
        /* bit 8 - always reset */
        /* bit 7 - always set */
        /* bit 6 - extension indicator, signals another byte */
        /* bit 5 - reserved */
        if (G[3].size != cs94) scss += 8;
        if (G[2].size != cs94) scss += 4;
        if (G[1].size != cs94) scss += 2;
        if (G[0].size != cs94) scss += 1;

        _snprintf(response, 100,
            "%d;%d;%d;%c;%c;%c;%c;%c;%c;%s%s%s%s",
            wherey[VTERM] - (relcursor ? vscrn_c_page_margin_top(VTERM) - 1: 0),
            wherex[VTERM] - (relcursor ? vscrn_c_page_margin_left(VTERM) - 1: 0),
            vscrn_current_page_number(VTERM, FALSE) + 1,
            srend,
            satt,
            sflag,
            pgl,
            pgr,
            scss,
            csetchar(G[0].size, G[0].designation),
            csetchar(G[1].size, G[1].designation),
            csetchar(G[2].size, G[2].designation),
            csetchar(G[3].size, G[3].designation)
            );
        break;
    }
    case 2: { /* DECTABSR - Tabulation Stop Report */
        int tabpos = 2, i;
        /* There is usually a tabstop at column 1, but we
         * don't report that here as the VT520 doesn't let
         * you place a tabstop a column 1, and K95 won't tab
         * to a tabstop in column 1 (unless its backtab,
         * which is probably what its there for) */
        for (i = 2; i < VscrnGetWidth(VTERM); i++) {
            if (htab[i] == 'T') {
                if (response[0] != '\0') strcat(response, "/");
                strcat(response, ckitoa(tabpos));
            }
            tabpos++;
        }
        break;
    }
    case 0: /* Ignored, nothing sent */
    default:
        break;
    }

    if (response[0] != '\0') {
        int buflen = strlen(response) + 10;
        decrqpsr = malloc(buflen);

        /* Send DCS pn[1] $ u response ST */
        if ( send_c1 )
            _snprintf(decrqpsr, buflen, "%c%d$u%s%c",
                _DCS, report, response, _ST8);
        else
            _snprintf(decrqpsr, buflen, "%cP%d$u%s%c\\",
                ESC, report, response, ESC);
        sendchars(decrqpsr,strlen(decrqpsr));

        free(decrqpsr);
    }
}


/*----------------------------------------------------------+----------------*/
/* color_table_report                                       | Page: n/a      */
/*----------------------------------------------------------+----------------*/
/* Sends a Color Table Report (DECCTR) for the currently selected palette to
 * the host. This can later be restored via DECRSTS.
 *
 * Available in: VT525, K95 */
void
color_table_report(int coordinate_system) {
    /* Response is: DCS 2 $ s D...D ST
     * Where D...D is consists of groups of five parameters separated by the '/'
     * character. Eg:
     *    1;2;3;4;5/1;2;3;4;5/1;2;3;4;5/...
     * Where:
     *   1 is the colour number (0-255)
     *   2 is the coordinate system (1=HLS, 2=RGB)
     *   3 is either hue (0-360) or red (0-100)
     *   4 is either lightness (0-100) or green (0-100)
     *   5 is either saturation (0-100) or blue (0-100)
     * So a single color is 17 bytes. A response containing a full 256
     * characters would be at most 4,614 bytes:
     *     256*17 + 255 (for the '/' characters) plus a few more for the DCS,
     *     ST, 2, $ and s
     * thats really too big for sendescseq so we'll need to deal with the C0/C1
     * situation ourselves and send it with sendchars.
     */
#define DECCTRBUFLEN 5000
    int i = 0, j=0;
    unsigned char max_color;
    unsigned long* palette;
    unsigned long bgr;
    char roundbuf[10];
    char* response = (char*)malloc(DECCTRBUFLEN);
    memset( response, 0, DECCTRBUFLEN ) ;
    memset( roundbuf, 0, 10 ) ;
    max_color = current_palette_max_index();
    palette = current_palette_rgb_table();

    if (send_c1) {
        response[i++] = _DCS;
    } else {
        response[i++] = ESC;
        response[i++] = 'P';
    }
    response[i++] = '2';
    response[i++] = '$';
    response[i++] = 's';

    for (j = 0; j <= max_color; j++) {
        unsigned char palindex, palr, palg, palb;
        palindex = color_index_to_vio(j);
        bgr = palette[palindex];
        palb = (bgr & 0x00FF0000)>>16;
        palg = (bgr & 0x0000FF00)>>8;
        palr = (bgr & 0x000000FF);

        /* Color number */
        i += ckstrncat(response, ckitoa(j), DECCTRBUFLEN);
        response[i++] = ';';

        if (coordinate_system == 1) {  /* HLS */
            float h, l, s;

            rgb_to_hls(palr, palg, palb, &h, &l, &s);

            /* Coordinate system */
            response[i++] = '1';
            response[i++] = ';';

            /* We say roundbuf is one smaller than it is so the null temrination
             * doesn't get overwritten as internally ckround just uses strncpy.
             * to return the result as a string. */
            ckround(h, 0, roundbuf, 9);
            i += ckstrncat(response, roundbuf, DECCTRBUFLEN);
            response[i++] = ';';
            ckround(l, 0, roundbuf, 9);
            i += ckstrncat(response, roundbuf, DECCTRBUFLEN);
            response[i++] = ';';
            ckround(s, 0, roundbuf, 9);
            i += ckstrncat(response, roundbuf, DECCTRBUFLEN);
        } else { /* RGB */
            unsigned char r, g, b;
            /* Convert from 0-255 range to 0-100 */
            r = (unsigned char)(palr / 255.0 * 100.0);
            g = (unsigned char)(palg / 255.0 * 100.0);
            b = (unsigned char)(palb / 255.0 * 100.0);

            /* Coordinate system */
            response[i++] = '2';
            response[i++] = ';';

            /* R, G, B */
            i += ckstrncat(response, ckitoa(r), DECCTRBUFLEN);
            response[i++] = ';';
            i += ckstrncat(response, ckitoa(g), DECCTRBUFLEN);
            response[i++] = ';';
            i += ckstrncat(response, ckitoa(b), DECCTRBUFLEN);
        }

        if (j < max_color) response[i++] = '/';
    }

    if (send_c1) {
        response[i++] = _ST8;
    } else {
        response[i++] = ESC;
        response[i++] = '\\';
    }
    response[i++] = '\0';

    sendchars(response, strlen(response));

    free(response);
#undef DECCTRBUFLEN
}

/*----------------------------------------------------------+----------------*/
/* restore_color_table                                      | Page: n/a      */
/*----------------------------------------------------------+----------------*/
/* Restores the current color palette using supplied values in the same format
 * as DECCTR. Input lives in the apc buffer
 *
 * Available in: VT525, K95 */
void
restore_color_table(int dcsnext)
{
    int palmax;
    ULONG *palette;

    palmax = current_palette_max_index();
    palette = current_palette_rgb_table();

    debug(F101, "Processing DCS string from", 0, dcsnext);

    /* Format is:
     *  Pc;Pu;Px;Py;Pz/Pc;Pu;Px;Py;Pz......
     */
    while(dcsnext<apclength) {
        int values[5] = {0,0,0,0,0};
        int i = 0;

        do {
            achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;

            if (i > 4) {
                /* Invalid entry with more than five values. Skip
                 * TODO: What does a real VT525 do? Does it abandon the whole
                 * restore, or just skip this entry?*/
                debug(F101, "Parameter limit exceeded for entry with index", 0, values[0]);
                i = -1;
                break;
            }

            while (isdigit(achar)) {            /* Get number */
                values[i] = (values[i] * 10) + achar - 48;
                achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
            }
            i++;
        } while (achar == ';');

        if (i == -1) {
            continue;    /* Bad entry - skip it */
        }

        debug(F100, "--------------------------------", 0, 0);
        debug(F101, "Got definition for palette entry", "index", values[0]);
        debug(F111, "Got definition for palette entry", "cspac", values[1]);
        debug(F111, "Got definition for palette entry", "val 1", values[2]);
        debug(F111, "Got definition for palette entry", "val 2", values[3]);
        debug(F111, "Got definition for palette entry", "val 3", values[4]);

        if (values[0] <= palmax) {
            int r, g, b;
            if (values[1] == 1) {    /* HLS format */
                debug(F101, "Palette entry in HLS format", 0, values[0]);
                hls_to_rgb(values[2], values[3], values[4], &r, &g, &b);
            } else if (values[1] == 2) { /* RGB format */
                debug(F101, "Palette entry in RGB format", 0, values[0]);
                r = K95ROUND((values[2]/100.0) * 255);
                g = K95ROUND((values[3]/100.0) * 255);
                b = K95ROUND((values[4]/100.0) * 255);
            } else {   /* Invalid format */
                continue;
            }
            debug(F111, "Got definition for palette entry", "red  ", r);
            debug(F111, "Got definition for palette entry", "green", g);
            debug(F111, "Got definition for palette entry", "blue ", b);

            palette[color_index_to_vio(values[0])] =
                               (unsigned)(((unsigned)b << 16) |
                               (unsigned)((unsigned)g << 8) |
                               (unsigned)r);
        }
    }
    VscrnIsDirty(VTERM);
}


void
set_declrmm(bool enabled) {
	if (IS_DECLRMM_AVAILABLE(tt_type_mode)) {
		declrmm = enabled;

		if (declrmm) {
			/* Clear DECDHL/DECDWL line attributes on all pages */
			int p, l;
			videoline * line;
			for (l = 0; l < VscrnGetHeight(vmode)-(tt_status[VTERM]?1:0); l++) {
				for (p = 0; p < vscrn[VTERM].page_count; p++) {
					line = VscrnGetPageLineFromTop(VTERM, l, p) ;
					if (line) {
						line->vt_line_attr = VT_LINE_ATTR_NORMAL;
					}
				}
			}
		} else {
		    int p;
			/* Reset margins on all pages to the far left/right */
			for (p = 0; p < vscrn[VTERM].page_count; p++) {
				vscrn_set_page_margin_left(VTERM, p, 1);
				vscrn_set_page_margin_right(VTERM, p, VscrnGetWidth(VTERM));
			}
		}
	}
}


/*---------------------------------------------------------------------------*/
/* naws                                                                      */
/*---------------------------------------------------------------------------*/
/* Negotiate About Window Size - let the remote host (if there is one) know the
 * window size has changed. How this is done depends on the protocol in use. */
void
naws() {
#ifdef TCPSOCKET
#ifdef CK_NAWS
    if (TELOPT_ME(TELOPT_NAWS) && ttmdm < 0) {
        tn_snaws();
#ifdef RLOGCODE
        rlog_naws();
#endif /* RLOGCODE */
#ifdef SSHBUILTIN
        ssh_snaws();
#endif /* SSHBUILTIN */
    }
#endif /* CK_NAWS */
#endif /* TCPSOCKET */
}


void
udkreset( void )
{
    int i;
    udklock = FALSE;                   /* Unlock User Defined Keys */
    for ( i=0 ; i<200 ; i++ )          /* Reset the User Defined Keys */
    {
       if ( udkfkeys[i] )
         free(udkfkeys[i]);
        udkfkeys[i] = NULL ;
    }

    if ( ISTVI(tt_type_mode) ) {
        udkfkeys[0]  = strdup("\01@\r");        /* F1 */
        udkfkeys[1]  = strdup("\01A\r");
        udkfkeys[2]  = strdup("\01B\r");
        udkfkeys[3]  = strdup("\01C\r");
        udkfkeys[4]  = strdup("\01D\r");
        udkfkeys[5]  = strdup("\01E\r");
        udkfkeys[6]  = strdup("\01F\r");
        udkfkeys[7]  = strdup("\01G\r");
        udkfkeys[8]  = strdup("\01H\r");
        udkfkeys[9]  = strdup("\01I\r");
        udkfkeys[10] = strdup("\01J\r");
        udkfkeys[11] = strdup("\01K\r");
        udkfkeys[12] = strdup("\01L\r");
        udkfkeys[13] = strdup("\01M\r");
        udkfkeys[14] = strdup("\01N\r");
        udkfkeys[15] = strdup("\01O\r");        /* F16 */
        udkfkeys[16] = strdup("\01`\r");        /* Shift-F1 */
        udkfkeys[17] = strdup("\01a\r");
        udkfkeys[18] = strdup("\01b\r");
        udkfkeys[19] = strdup("\01c\r");
        udkfkeys[20] = strdup("\01d\r");
        udkfkeys[21] = strdup("\01e\r");
        udkfkeys[22] = strdup("\01f\r");
        udkfkeys[23] = strdup("\01g\r");
        udkfkeys[24] = strdup("\01h\r");
        udkfkeys[25] = strdup("\01i\r");
        udkfkeys[26] = strdup("\01j\r");
        udkfkeys[27] = strdup("\01k\r");
        udkfkeys[28] = strdup("\01l\r");
        udkfkeys[29] = strdup("\01m\r");
        udkfkeys[30] = strdup("\01n\r");
        udkfkeys[31] = strdup("\01o\r");        /* Shift-F16 */
        udkfkeys[32] = strdup("\x08");          /* Backspace */
        udkfkeys[33] = strdup("\x1BT");         /* Clr Line */
        udkfkeys[34] = strdup("\x1Bt");         /* Shift Clr Line */
        udkfkeys[35] = strdup("\x1BY");         /* Clr Page */
        udkfkeys[36] = strdup("\x1By");         /* Shift Clr Page */
        udkfkeys[37] = strdup("\x1BW");         /* Del Char */
        udkfkeys[38] = strdup("\x1BR");         /* Del Line */
        udkfkeys[39] = strdup("\x0D");          /* Enter */
        udkfkeys[40] = strdup("\x1B");          /* Escape */
        udkfkeys[41] = strdup("\x1E");          /* Home */
        udkfkeys[42] = strdup("\x1B{");         /* Shift Home */
        udkfkeys[43] = strdup("\x1Bq");         /* Insert */
        udkfkeys[44] = strdup("\x1BQ");         /* Ins Char */
        udkfkeys[45] = strdup("\x1B\x45");      /* Ins Line */
        udkfkeys[46] = strdup("\x1BK");         /* Page Next*/
        udkfkeys[47] = strdup("\x1BJ");         /* Page Prev*/
        udkfkeys[48] = strdup("\x1Br");         /* Replace */
        udkfkeys[49] = strdup("\x0D");          /* Return */
        udkfkeys[50] = strdup("\x09");          /* Tab */
        udkfkeys[51] = strdup("\x1BI");         /* Shift Tab */
        udkfkeys[52] = strdup("\x1BP");         /* Print Screen */
        udkfkeys[53] = NULL;                    /* Shift Esc */
        udkfkeys[54] = strdup("\x08");          /* Shift BS */
        udkfkeys[55] = NULL ;                   /* Shift Enter */
        udkfkeys[56] = NULL ;                   /* Shift Return */
        udkfkeys[57] = strdup("\x0b");          /* Up Arrow - VT */
        udkfkeys[58] = strdup("\x16");          /* Dn Arrow - SYN */
        udkfkeys[59] = strdup("\x08");          /* Left Arrow - BS */
        udkfkeys[60] = strdup("\x0C");          /* Right Arrow - FF */
        udkfkeys[61] = NULL ;                   /* Shift Up Arrow */
        udkfkeys[62] = NULL ;                   /* Shift Dn Arrow */
        udkfkeys[63] = NULL ;                   /* Shift Left Arrow */
        udkfkeys[64] = NULL ;                   /* Shift Right Arrow */
        udkfkeys[65] = strdup("\0337");         /* Send */
        udkfkeys[66] = strdup("\0336");         /* Shift-Send */
    }

    if ( ISWYSE(tt_type_mode) ) {
        udkfkeys[0]  = strdup("\01@\r");        /* F1 */
        udkfkeys[1]  = strdup("\01A\r");
        udkfkeys[2]  = strdup("\01B\r");
        udkfkeys[3]  = strdup("\01C\r");
        udkfkeys[4]  = strdup("\01D\r");
        udkfkeys[5]  = strdup("\01E\r");
        udkfkeys[6]  = strdup("\01F\r");
        udkfkeys[7]  = strdup("\01G\r");
        udkfkeys[8]  = strdup("\01H\r");
        udkfkeys[9]  = strdup("\01I\r");
        udkfkeys[10] = strdup("\01J\r");
        udkfkeys[11] = strdup("\01K\r");
        udkfkeys[12] = strdup("\01L\r");
        udkfkeys[13] = strdup("\01M\r");
        udkfkeys[14] = strdup("\01N\r");
        udkfkeys[15] = strdup("\01O\r");
        udkfkeys[16] = strdup("\01P\r");
        udkfkeys[17] = strdup("\01Q\r");
        udkfkeys[18] = strdup("\01R\r");
        udkfkeys[19] = strdup("\01S\r");        /* F20 */

        udkfkeys[20] = strdup("\01`\r");        /* Shift-F1 */
        udkfkeys[21] = strdup("\01a\r");
        udkfkeys[22] = strdup("\01b\r");
        udkfkeys[23] = strdup("\01c\r");
        udkfkeys[24] = strdup("\01d\r");
        udkfkeys[25] = strdup("\01e\r");
        udkfkeys[26] = strdup("\01f\r");
        udkfkeys[27] = strdup("\01g\r");
        udkfkeys[28] = strdup("\01h\r");
        udkfkeys[29] = strdup("\01i\r");
        udkfkeys[30] = strdup("\01j\r");
        udkfkeys[31] = strdup("\01k\r");
        udkfkeys[32] = strdup("\01l\r");
        udkfkeys[33] = strdup("\01m\r");
        udkfkeys[34] = strdup("\01n\r");
        udkfkeys[35] = strdup("\01o\r");
        udkfkeys[36] = strdup("\01p\r");
        udkfkeys[37] = strdup("\01q\r");
        udkfkeys[38] = strdup("\01r\r");
        udkfkeys[39] = strdup("\01s\r");        /* Shift-F20 */

        udkfkeys[40] = strdup("\x08");          /* Backspace */
        udkfkeys[41] = strdup("\x1BT");         /* Clr Line */
        udkfkeys[42] = strdup("\x1Bt");         /* Shift Clr Line */
        udkfkeys[43] = strdup("\x1BY");         /* Clr Page */
        udkfkeys[44] = strdup("\x1By");         /* Shift Clr Page */
        udkfkeys[45] = strdup("\x1BW");         /* Del Char */
        udkfkeys[46] = strdup("\x1BR");         /* Del Line */
        udkfkeys[47] = strdup("\x0D");          /* Enter */
        udkfkeys[48] = strdup("\x1B");          /* Escape */
        udkfkeys[49] = strdup("\x1E");          /* Home */
        udkfkeys[50] = strdup("\x1B{");         /* Shift Home */
        udkfkeys[51] = strdup("\x1Bq");         /* Insert */
        udkfkeys[52] = strdup("\x1BQ");         /* Ins Char */
        udkfkeys[53] = strdup("\x1B\x45");      /* Ins Line */
        udkfkeys[54] = strdup("\x1BK");         /* Page Next*/
        udkfkeys[55] = strdup("\x1BJ");         /* Page Prev*/
        udkfkeys[56] = strdup("\x1Br");         /* Replace */
        udkfkeys[57] = strdup("\x0D");          /* Return */
        udkfkeys[58] = strdup("\x09");          /* Tab */
        udkfkeys[59] = strdup("\x1BI");         /* Shift Tab */
        udkfkeys[60] = strdup("\x1BP");         /* Print Screen */
        udkfkeys[61] = NULL;                    /* Shift Esc */
        udkfkeys[62] = strdup("\x08");          /* Shift BS */
        udkfkeys[63] = NULL ;                   /* Shift Enter */
        udkfkeys[64] = NULL ;                   /* Shift Return */
        udkfkeys[65] = strdup("\x0b");          /* Up Arrow - VT */
        udkfkeys[66] = strdup("\x0a");          /* Dn Arrow - LF */
        udkfkeys[67] = strdup("\x08");          /* Left Arrow - BS */
        udkfkeys[68] = strdup("\x0c");          /* Right Arrow - NL */
        udkfkeys[69] = NULL ;                   /* Shift Up Arrow */
        udkfkeys[70] = NULL ;                   /* Shift Dn Arrow */
        udkfkeys[71] = NULL ;                   /* Shift Left Arrow */
        udkfkeys[72] = NULL ;                   /* Shift Right Arrow */
        udkfkeys[73] = strdup("\x1B\x37");      /* Send */
        udkfkeys[74] = NULL ;                   /* Shift Send */
    }

    if ( ISAT386(tt_type_mode) ) {
        udkfkeys[0]  = strdup("\x1BOP");
        udkfkeys[1]  = strdup("\x1BOQ");
        udkfkeys[2]  = strdup("\x1BOR");
        udkfkeys[3]  = strdup("\x1BOS");
        udkfkeys[4]  = strdup("\x1BOT");
        udkfkeys[5]  = strdup("\x1BOU");
        udkfkeys[6]  = strdup("\x1BOV");
        udkfkeys[7]  = strdup("\x1BOW");
        udkfkeys[8]  = strdup("\x1BOX");
        udkfkeys[9]  = strdup("\x1BOY");
        udkfkeys[10] = strdup("\x1BOZ");
        udkfkeys[11] = strdup("\x1BOA");
        udkfkeys[12] = strdup("\x1BOp");
        udkfkeys[13] = strdup("\x1BOq");
        udkfkeys[14] = strdup("\x1BOr");
        udkfkeys[15] = strdup("\x1BOs");
        udkfkeys[16] = strdup("\x1BOt");
        udkfkeys[17] = strdup("\x1BOu");
        udkfkeys[18] = strdup("\x1BOv");
        udkfkeys[19] = strdup("\x1BOw");
        udkfkeys[20] = strdup("\x1BOx");
        udkfkeys[21] = strdup("\x1BOy");
        udkfkeys[22] = strdup("\x1BOz");
        udkfkeys[23] = strdup("\x1BOa");
        udkfkeys[24] = strdup("\x1BOP");
        udkfkeys[25] = strdup("\x1BOQ");
        udkfkeys[26] = strdup("\x1BOR");
        udkfkeys[27] = strdup("\x1BOS");
        udkfkeys[28] = strdup("\x1BOT");
        udkfkeys[29] = strdup("\x1BOU");
        udkfkeys[30] = strdup("\x1BOV");
        udkfkeys[31] = strdup("\x1BOW");
        udkfkeys[32] = strdup("\x1BOX");
        udkfkeys[33] = strdup("\x1BOY");
        udkfkeys[34] = strdup("\x1BOZ");
        udkfkeys[35] = strdup("\x1BOA");
        udkfkeys[36] = strdup("\x1BOp");
        udkfkeys[37] = strdup("\x1BOq");
        udkfkeys[38] = strdup("\x1BOr");
        udkfkeys[39] = strdup("\x1BOs");
        udkfkeys[40] = strdup("\x1BOt");
        udkfkeys[41] = strdup("\x1BOu");
        udkfkeys[42] = strdup("\x1BOv");
        udkfkeys[43] = strdup("\x1BOw");
        udkfkeys[44] = strdup("\x1BOx");
        udkfkeys[45] = strdup("\x1BOy");
        udkfkeys[46] = strdup("\x1BOz");
        udkfkeys[47] = strdup("\x1BOa");
        udkfkeys[48] = strdup("\x1B[H");
        udkfkeys[49] = strdup("\x1B[A");
        udkfkeys[50] = strdup("\x1B[V");
        udkfkeys[51] = strdup("\x1B[S");
        udkfkeys[52] = strdup("\x1B[D");
        udkfkeys[53] = strdup("\x1B[G");
        udkfkeys[54] = strdup("\x1B[C");
        udkfkeys[55] = strdup("\x1B[T");
        udkfkeys[56] = strdup("\x1B[Y");
        udkfkeys[57] = strdup("\x1B[B");
        udkfkeys[58] = strdup("\x1B[U");
        udkfkeys[59] = strdup("\x1B[@");
        udkfkeys[60] = strdup("\x1B[2");
    }

    if ( ISSCO(tt_type_mode) ) {
        udkfkeys[0]  = strdup("\x1B[M");
        udkfkeys[1]  = strdup("\x1B[N");
        udkfkeys[2]  = strdup("\x1B[O");
        udkfkeys[3]  = strdup("\x1B[P");
        udkfkeys[4]  = strdup("\x1B[Q");
        udkfkeys[5]  = strdup("\x1B[R");
        udkfkeys[6]  = strdup("\x1B[S");
        udkfkeys[7]  = strdup("\x1B[T");
        udkfkeys[8]  = strdup("\x1B[U");
        udkfkeys[9]  = strdup("\x1B[V");
        udkfkeys[10] = strdup("\x1B[W");
        udkfkeys[11] = strdup("\x1B[X");
        udkfkeys[12] = strdup("\x1B[Y");
        udkfkeys[13] = strdup("\x1B[Z");
        udkfkeys[14] = strdup("\x1B[a");
        udkfkeys[15] = strdup("\x1B[b");
        udkfkeys[16] = strdup("\x1B[c");
        udkfkeys[17] = strdup("\x1B[d");
        udkfkeys[18] = strdup("\x1B[e");
        udkfkeys[19] = strdup("\x1B[f");
        udkfkeys[20] = strdup("\x1B[g");
        udkfkeys[21] = strdup("\x1B[h");
        udkfkeys[22] = strdup("\x1B[i");
        udkfkeys[23] = strdup("\x1B[j");
        udkfkeys[24] = strdup("\x1B[k");
        udkfkeys[25] = strdup("\x1B[l");
        udkfkeys[26] = strdup("\x1B[m");
        udkfkeys[27] = strdup("\x1B[n");
        udkfkeys[28] = strdup("\x1B[o");
        udkfkeys[29] = strdup("\x1B[p");
        udkfkeys[30] = strdup("\x1B[q");
        udkfkeys[31] = strdup("\x1B[r");
        udkfkeys[32] = strdup("\x1B[s");
        udkfkeys[33] = strdup("\x1B[t");
        udkfkeys[34] = strdup("\x1B[u");
        udkfkeys[35] = strdup("\x1B[v");
        udkfkeys[36] = strdup("\x1B[w");
        udkfkeys[37] = strdup("\x1B[x");
        udkfkeys[38] = strdup("\x1B[y");
        udkfkeys[39] = strdup("\x1B[z");
        udkfkeys[40] = strdup("\x1B[@");
        udkfkeys[41] = strdup("\x1B[[");
        udkfkeys[42] = strdup("\x1B[\\");
        udkfkeys[43] = strdup("\x1B[]");
        udkfkeys[44] = strdup("\x1B[^");
        udkfkeys[45] = strdup("\x1B[_");
        udkfkeys[46] = strdup("\x1B[`");
        udkfkeys[47] = strdup("\x1B[{");
        udkfkeys[48] = strdup("\x1B[H");
        udkfkeys[49] = strdup("\x1B[A");
        udkfkeys[50] = strdup("\x1B[I");
        udkfkeys[51] = strdup("-");
        udkfkeys[52] = strdup("\x1B[D");
        udkfkeys[53] = strdup("\x1B[E");
        udkfkeys[54] = strdup("\x1B[C");
        udkfkeys[55] = strdup("+");
        udkfkeys[56] = strdup("\x1B[F");
        udkfkeys[57] = strdup("\x1B[B");
        udkfkeys[58] = strdup("\x1B[G");
        udkfkeys[59] = strdup("\x1B[L");
    }

    if ( ISLINUX(tt_type_mode) ) {
        udkfkeys[0]  = strdup("\x1B[[A");
        udkfkeys[1]  = strdup("\x1B[[B");
        udkfkeys[2]  = strdup("\x1B[[C");
        udkfkeys[3]  = strdup("\x1B[[D");
        udkfkeys[4]  = strdup("\x1B[[E");
        udkfkeys[5]  = strdup("\x1B[17~");
        udkfkeys[6]  = strdup("\x1B[18~");
        udkfkeys[7]  = strdup("\x1B[19~");
        udkfkeys[8]  = strdup("\x1B[20~");
        udkfkeys[9]  = strdup("\x1B[21~");
        udkfkeys[10] = strdup("\x1B[23~");
        udkfkeys[11] = strdup("\x1B[24~");
        udkfkeys[12] = strdup("\x1B[25~");
        udkfkeys[13] = strdup("\x1B[26~");
        udkfkeys[14] = strdup("\x1B[28~");
        udkfkeys[15] = strdup("\x1B[29~");
        udkfkeys[16] = strdup("\x1B[31~");
        udkfkeys[17] = strdup("\x1B[32~");
        udkfkeys[18] = strdup("\x1B[33~");
        udkfkeys[19] = strdup("\x1B[34~");
        udkfkeys[20] = strdup("\x1B[35~");
        udkfkeys[21] = strdup("\x1B[36~");
        udkfkeys[22] = strdup("\x1B[37~");
        udkfkeys[23] = strdup("\x1B[38~");
        udkfkeys[24] = strdup("\x1B[39~");
        udkfkeys[25] = strdup("\x1B[40~");
        udkfkeys[26] = strdup("\x1B[41~");
        udkfkeys[27] = strdup("\x1B[42~");
        udkfkeys[28] = strdup("\x1B[43~");
        udkfkeys[29] = strdup("\x1B[44~");
        udkfkeys[30] = strdup("\x1B[45~");
        udkfkeys[31] = strdup("\x1B[46~");
        udkfkeys[32] = strdup("\x1B[47~");
        udkfkeys[33] = strdup("\x1B[48~");
        udkfkeys[34] = strdup("\x1B[49~");
        udkfkeys[35] = strdup("\x1B[50~");
        udkfkeys[36] = strdup("\x1B[51~");
        udkfkeys[37] = strdup("\x1B[52~");
        udkfkeys[38] = strdup("\x1B[53~");
        udkfkeys[39] = strdup("\x1B[54~");
        udkfkeys[40] = strdup("\x1B[55~");
        udkfkeys[41] = strdup("\x1B[56~");
        udkfkeys[42] = strdup("\x1B[57~");
        udkfkeys[43] = strdup("\x1B[58~");
        udkfkeys[44] = strdup("\x1B[59~");
        udkfkeys[45] = strdup("\x1B[60~");
        udkfkeys[46] = strdup("\x1B[61~");
        udkfkeys[47] = strdup("\x1B[62~");
        udkfkeys[48] = strdup("\x1B[1~");       /* home */
        udkfkeys[49] = strdup("\x1B[A");        /* up */
        udkfkeys[50] = strdup("\x1B[5~");
        udkfkeys[51] = strdup("-");
        udkfkeys[52] = strdup("\x1B[D");
        udkfkeys[53] = strdup("\x1B[G");
        udkfkeys[54] = strdup("\x1B[C");
        udkfkeys[55] = strdup("+");
        udkfkeys[56] = strdup("\x1B[4~");
        udkfkeys[57] = strdup("\x1B[B");
        udkfkeys[58] = strdup("\x1B[6~");
        udkfkeys[59] = strdup("\x1B[2~");
        udkfkeys[60] = strdup("\x1B[3~");
    }

    if ( ISHP(tt_type_mode) ) {
        udkfkeys[0]  = strdup("\x1Bp");
        udkfkeys[1]  = strdup("\x1Bq");
        udkfkeys[2]  = strdup("\x1Br");
        udkfkeys[3]  = strdup("\x1Bs");
        udkfkeys[4]  = strdup("\x1Bt");
        udkfkeys[5]  = strdup("\x1Bu");
        udkfkeys[6]  = strdup("\x1Bv");
        udkfkeys[7]  = strdup("\x1Bw");
        udkfkeys[8]  = NULL;
        udkfkeys[9]  = NULL;
        udkfkeys[10] = NULL;
        udkfkeys[11] = NULL;
        udkfkeys[12] = NULL;
        udkfkeys[13] = NULL;
        udkfkeys[14] = NULL;
        udkfkeys[15] = NULL;
        udkfkeys[16] = strdup("\x1Bi");
        udkfkeys[17] = strdup("\r");
        udkfkeys[18] = strdup("\r");
    }

    if ( ISDG200(tt_type_mode) ) {
        /* function keys */
        udkfkeys[0]  = strdup("\036q");
        udkfkeys[1]  = strdup("\036r");
        udkfkeys[2]  = strdup("\036s");
        udkfkeys[3]  = strdup("\036t");
        udkfkeys[4]  = strdup("\036u");
        udkfkeys[5]  = strdup("\036v");
        udkfkeys[6]  = strdup("\036w");
        udkfkeys[7]  = strdup("\036x");
        udkfkeys[8]  = strdup("\036y");
        udkfkeys[9]  = strdup("\036z");
        udkfkeys[10] = strdup("\036{");
        udkfkeys[11] = strdup("\036|");
        udkfkeys[12] = strdup("\036}");
        udkfkeys[13] = strdup("\036~");
        udkfkeys[14] = strdup("\036p");
        udkfkeys[15] = strdup("\036a");
        udkfkeys[16] = strdup("\036b");
        udkfkeys[17] = strdup("\036c");
        udkfkeys[18] = strdup("\036d");
        udkfkeys[19] = strdup("\036e");
        udkfkeys[20] = strdup("\036f");
        udkfkeys[21] = strdup("\036g");
        udkfkeys[22] = strdup("\036h");
        udkfkeys[23] = strdup("\036i");
        udkfkeys[24] = strdup("\036j");
        udkfkeys[25] = strdup("\036k");
        udkfkeys[26] = strdup("\036l");
        udkfkeys[27] = strdup("\036m");
        udkfkeys[28] = strdup("\036n");
        udkfkeys[29] = strdup("\036`");
        udkfkeys[30] = strdup("\0361");
        udkfkeys[31] = strdup("\0362");
        udkfkeys[32] = strdup("\0363");
        udkfkeys[33] = strdup("\0364");
        udkfkeys[34] = strdup("\0365");
        udkfkeys[35] = strdup("\0366");
        udkfkeys[36] = strdup("\0367");
        udkfkeys[37] = strdup("\0368");
        udkfkeys[38] = strdup("\0369");
        udkfkeys[39] = strdup("\036:");
        udkfkeys[40] = strdup("\036;");
        udkfkeys[41] = strdup("\036<");
        udkfkeys[42] = strdup("\036=");
        udkfkeys[43] = strdup("\036>");
        udkfkeys[44] = strdup("\0360");
        udkfkeys[45] = strdup("\036!");
        udkfkeys[46] = strdup("\036\"");
        udkfkeys[47] = strdup("\036#");
        udkfkeys[48] = strdup("\036$");
        udkfkeys[49] = strdup("\036%");
        udkfkeys[50] = strdup("\036&");
        udkfkeys[51] = strdup("\036'");
        udkfkeys[52] = strdup("\036(");
        udkfkeys[53] = strdup("\036)");
        udkfkeys[54] = strdup("\036*");
        udkfkeys[55] = strdup("\036+");
        udkfkeys[56] = strdup("\036,");
        udkfkeys[57] = strdup("\036-");
        udkfkeys[58] = strdup("\036.");
        udkfkeys[59] = strdup("\036 ");

        /* arrow keys - native */
        udkfkeys[60] = strdup("\027");
        udkfkeys[61] = strdup("\032");
        udkfkeys[62] = strdup("\031");
        udkfkeys[63] = strdup("\030");
        udkfkeys[64] = strdup("\036\027");
        udkfkeys[65] = strdup("\036\032");
        udkfkeys[66] = strdup("\036\031");
        udkfkeys[67] = strdup("\036\030");

        /* other - native */
        udkfkeys[68] = strdup("\014");
        udkfkeys[69] = strdup("\036\\");
        udkfkeys[70] = strdup("\036]");
        udkfkeys[71] = strdup("\013");
        udkfkeys[72] = strdup("\036^");
        udkfkeys[73] = strdup("\036_");
        udkfkeys[74] = strdup("\036\021");
        udkfkeys[75] = strdup("\010");
        udkfkeys[76] = strdup("\014");
        udkfkeys[77] = strdup("\036X");
        udkfkeys[78] = strdup("\036Y");
        udkfkeys[79] = strdup("\013");
        udkfkeys[80] = strdup("\036Z");
        udkfkeys[81] = strdup("\036{");
        udkfkeys[82] = strdup("\036\001");
        udkfkeys[83] = strdup("\031");
        udkfkeys[84] = strdup("\036\010");

        /* arrow keys - unix mode */
        udkfkeys[85] = strdup("\036PA");
        udkfkeys[86] = strdup("\036PB");
        udkfkeys[87] = strdup("\036PD");
        udkfkeys[88] = strdup("\036PC");
        udkfkeys[89] = strdup("\036Pa");
        udkfkeys[90] = strdup("\036Pb");
        udkfkeys[91] = strdup("\036Pd");
        udkfkeys[92] = strdup("\036Pc");

        /* other - unix mode */
        udkfkeys[93] = strdup("\036PH");
        udkfkeys[94] = strdup("\036\\");
        udkfkeys[95] = strdup("\036]");
        udkfkeys[96] = strdup("\036PE");
        udkfkeys[97] = strdup("\036^");
        udkfkeys[98] = strdup("\036_");
        udkfkeys[99] = strdup("\036P0");
        udkfkeys[100] = strdup("\036PF");
        udkfkeys[101] = strdup("\036PH");
        udkfkeys[102] = strdup("\036X");
        udkfkeys[103] = strdup("\036Y");
        udkfkeys[104] = strdup("\036PE");
        udkfkeys[105] = strdup("\036Z");
        udkfkeys[106] = strdup("\036[");
        udkfkeys[107] = strdup("\036P1");
        udkfkeys[108] = strdup("\177");
        udkfkeys[109] = strdup("\036Pf");
    }

    if ( IS97801(tt_type_mode) ) {
        udkfkeys[0]   = strdup("\033@");
        udkfkeys[1]   = strdup("\033A");
        udkfkeys[2]   = strdup("\033B");
        udkfkeys[3]   = strdup("\033C");
        udkfkeys[4]   = strdup("\033D");
        udkfkeys[5]   = strdup("\033F");
        udkfkeys[6]   = strdup("\033G");
        udkfkeys[7]   = strdup("\033H");
        udkfkeys[8]   = strdup("\033I");
        udkfkeys[9]   = strdup("\033J");
        udkfkeys[10]  = strdup("\033K");
        udkfkeys[11]  = strdup("\033L");
        udkfkeys[12]  = strdup("\033M");
        udkfkeys[13]  = strdup("\033N");
        udkfkeys[14]  = strdup("\033O");
        udkfkeys[15]  = strdup("\033P");
        udkfkeys[16]  = strdup("\0330");
        udkfkeys[17]  = strdup("\033_");
        udkfkeys[18]  = strdup("\033d");
        udkfkeys[19]  = strdup("\033T");
        udkfkeys[20]  = strdup("\033V");
        udkfkeys[21]  = strdup("\033X");
        udkfkeys[22]  = strdup("\0334");
        udkfkeys[23]  = strdup("\033g");
        udkfkeys[24]  = strdup("\x09");
        udkfkeys[25]  = strdup("\033[Z");
        udkfkeys[26]  = strdup("\033^");
        udkfkeys[27]  = strdup("\033>");
        udkfkeys[28]  = strdup("\033m");
        udkfkeys[29]  = strdup("\004");
        udkfkeys[30]  = strdup("\033[S");
        udkfkeys[31]  = strdup("\033[T");
        udkfkeys[32]  = strdup("\033[H");
        udkfkeys[33]  = strdup("\033[P");
        udkfkeys[34]  = strdup("\033[A");
        udkfkeys[35]  = strdup("\033p");
        udkfkeys[36]  = strdup("\033[D");
        udkfkeys[37]  = strdup("\033!");
        udkfkeys[38]  = strdup("\033[C");
        udkfkeys[39]  = strdup("\033[M");
        udkfkeys[40]  = strdup("\033[B");
        udkfkeys[41]  = strdup("00");
        udkfkeys[42]  = strdup("\033z");
        udkfkeys[43]  = strdup("\033]");
        udkfkeys[44]  = strdup("\033[@");
        udkfkeys[45]  = strdup("\033o");
        udkfkeys[46]  = strdup("\033[L");
        udkfkeys[47]  = strdup("\0336");
        udkfkeys[48]  = strdup("\0337");
        udkfkeys[49]  = strdup("\0338");
        udkfkeys[50]  = strdup("\033l");
        udkfkeys[51]  = strdup("\033Z");
        udkfkeys[52]  = strdup("\033 ");
        udkfkeys[53]  = strdup("\033;");
        udkfkeys[54]  = strdup("\033\"");
        udkfkeys[55]  = strdup("\033#");
        udkfkeys[56]  = strdup("\033$");
        udkfkeys[57]  = strdup("\033%");
        udkfkeys[58]  = strdup("\033&");
        udkfkeys[59]  = strdup("\033\\");
        udkfkeys[60]  = strdup("\033<");
        udkfkeys[61]  = strdup("\033=");
        udkfkeys[62]  = strdup("\033 ");
        udkfkeys[63]  = strdup("\033+");
        udkfkeys[64]  = strdup("\033,");
        udkfkeys[65]  = strdup("\033_");
        udkfkeys[66]  = strdup("\033.");
        udkfkeys[67]  = strdup("\033/");
        udkfkeys[68]  = strdup("\0331");
        udkfkeys[69]  = strdup("\0332");
        udkfkeys[70]  = strdup("\0333");
        udkfkeys[71]  = strdup("\033U");
        udkfkeys[72]  = strdup("\033W");
        udkfkeys[73]  = strdup("\033Y");
        udkfkeys[74]  = strdup("\0335");
        udkfkeys[75]  = strdup("\033g");
        udkfkeys[76]  = strdup("\033[Z");
        udkfkeys[77]  = strdup("\033[Z");
        udkfkeys[78]  = strdup("\033^");
        udkfkeys[79]  = strdup("\033>");
        udkfkeys[80]  = strdup("\033m");
        udkfkeys[81]  = strdup("\033~");
        udkfkeys[82]  = strdup("\033[S");
        udkfkeys[83]  = strdup("\033[T");
        udkfkeys[84]  = strdup("\033q");
        udkfkeys[85]  = strdup("\033[P");
        udkfkeys[86]  = strdup("\033[A");
        udkfkeys[87]  = strdup("\033p");
        udkfkeys[88]  = strdup("\0339");
        udkfkeys[89]  = strdup("\033~");
        udkfkeys[90]  = strdup("\033:");
        udkfkeys[91]  = strdup("\033[M");
        udkfkeys[92]  = strdup("\033[B");
        udkfkeys[93]  = strdup("00");
        udkfkeys[94]  = strdup("\033z");
        udkfkeys[95]  = strdup("\033]");
        udkfkeys[96]  = strdup("\033[@");
        udkfkeys[97]  = strdup("\033o");
        udkfkeys[98]  = strdup("\033[L");
        udkfkeys[99]  = strdup("\0336");
        udkfkeys[100]  = strdup("\0337");
        udkfkeys[101]  = strdup("\0338");
        udkfkeys[102] = strdup("\033l");
        udkfkeys[103] = strdup("\033Z");
        /* Ctrl key definitions default to NULL */
    }

    if ( ISBA80(tt_type_mode) ) {
        udkfkeys[0]   = strdup("\033[=N1\015");
        udkfkeys[1]   = strdup("\033[=N2\015");
        udkfkeys[2]   = strdup("\033[=N3\015");
        udkfkeys[3]   = strdup("\033[=N4\015");
        udkfkeys[4]   = strdup("\033[=N5\015");
        udkfkeys[5]   = strdup("\033[=N6\015");
        udkfkeys[6]   = strdup("\033[=N7\015");
        udkfkeys[7]   = strdup("\033[=N8\015");
        udkfkeys[8]   = strdup("\033[=N9\015");
        udkfkeys[9]   = strdup("\033[=>a");
        udkfkeys[10]  = strdup("\033[=>b");
        udkfkeys[11]  = strdup("\033[=>c");
        udkfkeys[12]  = strdup("\033[=>d");
        udkfkeys[13]  = strdup("\033[=>e");
        udkfkeys[14]  = strdup("\033[=>f");
        udkfkeys[15]  = strdup("\033[=>g");
        udkfkeys[16]  = strdup("\033[=>h");
        udkfkeys[17]  = strdup("\033[=>i");
        udkfkeys[18]  = strdup("\033[=>j");
        udkfkeys[19]  = strdup("\033[=>k");
        udkfkeys[20]  = strdup("\033[=>l");
        udkfkeys[21]  = strdup("\033[=>m");
        udkfkeys[22]  = strdup("\033[=>n");
        udkfkeys[23]  = strdup("\033[=>o");
        udkfkeys[24]  = strdup("\033[=>p");
        udkfkeys[25]  = strdup("\033[=>q");
        udkfkeys[26]  = strdup("\033[=>r");
        udkfkeys[27]  = strdup("\033[=>s");
        udkfkeys[28]  = strdup("\033[=>t");
        udkfkeys[29]  = strdup("\033[=>u");
        udkfkeys[30]  = strdup("\033[=>v");
        udkfkeys[31]  = strdup("\033[=>w");
        udkfkeys[32]  = strdup("\033[=>x");
        udkfkeys[33]  = strdup("\033[=<0");
        udkfkeys[34]  = strdup("\033[=<1");
        udkfkeys[35]  = strdup("\033[=<2");
        udkfkeys[36]  = strdup("\033[=<4");
        udkfkeys[37]  = strdup("\033[=<5");
        udkfkeys[38]  = strdup("\033[=<6");
        udkfkeys[39]  = strdup("\033[=<7");
        udkfkeys[40]  = strdup("\033[=<8");
        udkfkeys[41]  = strdup("\033[=<9");
        udkfkeys[42]  = strdup("\033[=<f");
        udkfkeys[43]  = strdup("\033[=<g");
        udkfkeys[44]  = strdup("\033[=<p");
        udkfkeys[45]  = strdup("\033[=<B");
        udkfkeys[46]  = strdup("\033[=<F");
        udkfkeys[47]  = strdup("\033[=<G");
        udkfkeys[48]  = strdup("\033[=<H");
        udkfkeys[49]  = strdup("\033[=<I");
        udkfkeys[50]  = strdup("\033[=<J");
        udkfkeys[51]  = strdup("\033[=<K");
        udkfkeys[52]  = strdup("\033[=<L");
        udkfkeys[53]  = strdup("\033[=<M");
        udkfkeys[54]  = strdup("\033[=<O");
        udkfkeys[55]  = strdup("\033[=<P");
        udkfkeys[56]  = strdup("\033[=<Q");
        udkfkeys[57]  = strdup("\033[=<R");
        udkfkeys[58]  = strdup("\033[=<T");
        udkfkeys[59]  = strdup("\033[=<U");
        udkfkeys[60]  = strdup("\033[=<V");
        udkfkeys[61]  = strdup("\033[=<W");
    }

    if (ISSUN(tt_type_mode)) {
        udkfkeys[0]   = strdup("\033[192z");   /* K_SUN_STOP        */
        udkfkeys[1]   = strdup("\033[193z");   /* K_SUN_AGAIN       */
        udkfkeys[2]   = strdup("\033[194z");   /* K_SUN_PROPS       */
        udkfkeys[3]   = strdup("\033[195z");   /* K_SUN_UNDO        */
        udkfkeys[4]   = strdup("\033[196z");   /* K_SUN_FRONT       */
        udkfkeys[5]   = strdup("\033[197z");   /* K_SUN_COPY        */
        udkfkeys[6]   = strdup("\033[198z");   /* K_SUN_OPEN        */
        udkfkeys[7]   = strdup("\033[199z");   /* K_SUN_PASTE       */
        udkfkeys[8]   = strdup("\033[200z");   /* K_SUN_FIND        */
        udkfkeys[9]   = strdup("\033[201z");   /* K_SUN_CUT         */
        udkfkeys[10]  = strdup("\033[207z");   /* K_SUN_HELP        */
    }

    if (ISIBM31(tt_type_mode)) {
        extern int i31_lta;
        int i,j;

        udkfkeys[0]   = strdup("\033a\003");   /* K_I31_F01         */
        udkfkeys[1]   = strdup("\033b\003");   /* K_I31_F02         */
        udkfkeys[2]   = strdup("\033c\003");   /* K_I31_F03         */
        udkfkeys[3]   = strdup("\033d\003");   /* K_I31_F04         */
        udkfkeys[4]   = strdup("\033e\003");   /* K_I31_F05         */
        udkfkeys[5]   = strdup("\033f\003");   /* K_I31_F06         */
        udkfkeys[6]   = strdup("\033g\003");   /* K_I31_F07         */
        udkfkeys[7]   = strdup("\033h\003");   /* K_I31_F08         */
        udkfkeys[8]   = strdup("\033i\003");   /* K_I31_F09         */
        udkfkeys[9]   = strdup("\033j\003");   /* K_I31_F10         */
        udkfkeys[10]  = strdup("\033k\003");   /* K_I31_F11         */
        udkfkeys[11]  = strdup("\033l\003");   /* K_I31_F12         */
        udkfkeys[12]  = strdup("\033!a\003");  /* K_I31_F13         */
        udkfkeys[13]  = strdup("\033!b\003");  /* K_I31_F14         */
        udkfkeys[14]  = strdup("\033!c\003");  /* K_I31_F15         */
        udkfkeys[15]  = strdup("\033!d\003");  /* K_I31_F16         */
        udkfkeys[16]  = strdup("\033!e\003");  /* K_I31_F17         */
        udkfkeys[17]  = strdup("\033!f\003");  /* K_I31_F18         */
        udkfkeys[18]  = strdup("\033!g\003");  /* K_I31_F19         */
        udkfkeys[19]  = strdup("\033!h\003");  /* K_I31_F20         */
        udkfkeys[20]  = strdup("\033!i\003");  /* K_I31_F21         */
        udkfkeys[21]  = strdup("\033!j\003");  /* K_I31_F22         */
        udkfkeys[22]  = strdup("\033!k\003");  /* K_I31_F23         */
        udkfkeys[23]  = strdup("\033!l\003");  /* K_I31_F24         */
        udkfkeys[24]  = strdup("\033\"a\003"); /* K_I31_F25         */
        udkfkeys[25]  = strdup("\033\"b\003"); /* K_I31_F26         */
        udkfkeys[26]  = strdup("\033\"c\003"); /* K_I31_F27         */
        udkfkeys[27]  = strdup("\033\"d\003"); /* K_I31_F28         */
        udkfkeys[28]  = strdup("\033\"e\003"); /* K_I31_F29         */
        udkfkeys[29]  = strdup("\033\"f\003"); /* K_I31_F30         */
        udkfkeys[30]  = strdup("\033\"g\003"); /* K_I31_F31         */
        udkfkeys[31]  = strdup("\033\"h\003"); /* K_I31_F32         */
        udkfkeys[32]  = strdup("\033\"i\003"); /* K_I31_F33         */
        udkfkeys[33]  = strdup("\033\"j\003"); /* K_I31_F34         */
        udkfkeys[34]  = strdup("\033\"k\003"); /* K_I31_F35         */
        udkfkeys[35]  = strdup("\033\"l\003"); /* K_I31_F36         */
        udkfkeys[36]  = strdup("\033!m\003");  /* K_I31_PA1         */
        udkfkeys[37]  = strdup("\033!n\003");  /* K_I31_PA2         */
        udkfkeys[38]  = strdup("\033!o\003");  /* K_I31_PA3         */
        udkfkeys[39]  = strdup("\033!z");      /* K_I31_RESET       */
        udkfkeys[40]  = strdup("\033\"A");     /* K_I31_JUMP        */
        udkfkeys[41]  = strdup("\033L\003");   /* K_I31_CLEAR       */
        udkfkeys[42]  = strdup("\033I");       /* K_I31_ERASE_EOF   */
        udkfkeys[43]  = strdup("\033J");       /* K_I31_ERASE_EOP   */
        udkfkeys[44]  = strdup("\033K");       /* K_I31_ERASE_INP   */
        udkfkeys[45]  = strdup("\033P");       /* K_I31_INSERT_CHAR */
        udkfkeys[46]  = strdup("\033P \008");  /* K_I31_INSERT_SPACE*/
        udkfkeys[47]  = strdup("\033Q");       /* K_I31_DELETE      */
        udkfkeys[48]  = strdup("\033N");       /* K_I31_INS_LN      */
        udkfkeys[49]  = strdup("\033O");       /* K_I31_DEL_LN      */
        udkfkeys[50]  = strdup("\033U\003");   /* K_I31_PRINT_LINE  */
        udkfkeys[51]  = strdup("\033V\003");   /* K_I31_PRINT_MSG   */
        udkfkeys[52]  = strdup("\033W\003");   /* K_I31_PRINT_SHIFT */
        udkfkeys[53]  = strdup("\033 W\003");  /* K_I31_CANCEL      */
        udkfkeys[54]  = strdup("\033!8\003");  /* K_I31_SEND_LINE   */
        udkfkeys[55]  = strdup("\033 8\003");  /* K_I31_SEND_MSG    */
        udkfkeys[56]  = strdup("\0338\003");   /* K_I31_SEND_PAGE   */
        udkfkeys[57]  = strdup("\033H");       /* K_I31_HOME        */
        udkfkeys[58]  = strdup("\0332");       /* K_I31_BACK_TAB    */

        if ( i31_lta != ETX ) {
            for ( i=0;i<=58;i++ ) {
                for ( j=strlen(udkfkeys[i])-1;j>=0;j-- ) {
                    if ( udkfkeys[i][j] == ETX )
                        udkfkeys[i][j] = i31_lta;
                }
            }
        }
    }
}

void
showudk( void )
{
#ifndef NOKVERBS
    int i;
    printf("\n%s User Defined Keys:\n",
            ISSCO(tt_type)?"SCOANSI":
            ISAT386(tt_type)?"AT386":
            ISLINUX(tt_type)?"LINUX":
            ISANSI(tt_type)?"ANSI":
            ISWYSE(tt_type)?"WYSE":
            ISTVI(tt_type)?"TVI":
            ISH19(tt_type)?"HEATH":
            ISDG200(tt_type)?"DG":
            ISHP(tt_type)?"HP":
            IS97801(tt_type)?"SNI 97801-5XX":
            ISBA80(tt_type)?"Nixdorf BA80":
            ISIBM31(tt_type)?"IBM 31x1":
            ISSUN(tt_type)?"SUN":
            "DEC VT");
    printf("  Lock: %s\n\n", udklock ? "on": "off" ) ;

    if ( IS97801(tt_type) ) {
        for ( i=0; i<(K_SNI_MAX-K_SNI_MIN+1) ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  snif%d = \\{%d}%s\n",i+1,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  snif%d = %s\n",i+1,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
    }
    else if ( ISSUN(tt_type) ) {
        for ( i=0; i<=10 ; i++ ) {
            char * s = "" ;
            switch ( i ) {
            case 0: s = "sunstop"  ; break ;
            case 1: s = "sunagain" ; break ;
            case 2: s = "sunprops" ; break ;
            case 3: s = "sunundo"  ; break ;
            case 4: s = "sunfront" ; break ;
            case 5: s = "suncopy"  ; break ;
            case 6: s = "sunopen"  ; break ;
            case 7: s = "sunpaste" ; break ;
            case 8: s = "sunfind"  ; break ;
            case 9: s = "suncut"   ; break ;
            case 10: s = "sunhelp" ; break ;
            }
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  %s = \\{%d}%s\n",s,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  %s = %s\n",s,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
    }
    else if ( ISUNIXCON(tt_type) ) {
        for ( i=0; i<61 ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  ansif%-3d = \\{%d}%s\n",i+1,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  ansif%-3d = %s\n",i+1,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
    } 
    else if ( ISVT100(tt_type) )
        for ( i=1; i<=20 ; i++ )
        {
            if ( udkfkeys[i-1] && udkfkeys[i-1][0] < SP ) {
                if ( i==15 )
                    printf("  udkdo   = \\{%d}%s\n",
                            udkfkeys[i-1][0],&(udkfkeys[i-1][1]));
                else if ( i==16 )
                    printf("  udkhelp = \\{%d}%s\n",
                            udkfkeys[i-1][0],&(udkfkeys[i-1][1]));
                else
                    printf("  udkf%-3d = \\{%d}%s\n",i,
                            udkfkeys[i-1][0],&(udkfkeys[i-1][1]));
            }
            else {
                if ( i==15 )
                    printf("  udkdo   = %s\n",
                            udkfkeys[i-1]?udkfkeys[i-1]:"(unassigned)");
                else if ( i==16 )
                    printf("  udkhelp = %s\n",
                            udkfkeys[i-1]?udkfkeys[i-1]:"(unassigned)");
                else
                    printf("  udkf%-3d = %s\n",i,
                            udkfkeys[i-1]?udkfkeys[i-1]:"(unassigned)");
            }
        }
    else if ( ISWYSE(tt_type) ) {
        for ( i=0; i<20 ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  wyf%-3d = \\{%d}%s\n",i+1,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  wyf%-3d = %s\n",i+1,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
        for ( i=20; i<40 ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  wysf%-3d = \\{%d}%s\n",i+1-20,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  wysf%-3d = %s\n",i+1-20,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
        for ( i=40; i<75 ; i++ ) {
            char * s = "" ;
            switch ( i ) {
            case 40: s = "wybs"         ; break ;
            case 41: s = "wyclrln"      ; break ;
            case 42: s = "wysclrln"     ; break ;
            case 43: s = "wyclrpg"      ; break ;
            case 44: s = "wysclrpg"     ; break ;
            case 45: s = "wydelchar"    ; break ;
            case 46: s = "wydelln"      ; break ;
            case 47: s = "wyenter"      ; break ;
            case 48: s = "wyesc"        ; break ;
            case 49: s = "wyhome"       ; break ;
            case 50: s = "wyshome"      ; break ;
            case 51: s = "wyinsert"     ; break ;
            case 52: s = "wyinschar"    ; break ;
            case 53: s = "wyinsln"      ; break ;
            case 54: s = "wypgnext"     ; break ;
            case 55: s = "wypgprev"     ; break ;
            case 56: s = "wyreplace"    ; break ;
            case 57: s = "wyreturn"     ; break ;
            case 58: s = "wytab"        ; break ;
            case 59: s = "wystab"       ; break ;
            case 60: s = "wyprtscn"     ; break ;
            case 61: s = "wysesc"       ; break ;
            case 62: s = "wysbs"        ; break ;
            case 63: s = "wysenter"     ; break ;
            case 64: s = "wysreturn"    ; break ;
            case 65: s = "wyuparr"      ; break ;
            case 66: s = "wydnarr"      ; break ;
            case 67: s = "wylfarr"      ; break ;
            case 68: s = "wyrtarr"      ; break ;
            case 69: s = "wysuparr"     ; break ;
            case 70: s = "wysdnarr"     ; break ;
            case 71: s = "wyslfarr"     ; break ;
            case 72: s = "wysrtarr"     ; break ;
            case 73: s = "wysend"       ; break ;
            case 74: s = "wyssend"      ; break ;
            }
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  %s = \\{%d}%s\n",s,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  %s = %s\n",s,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }

    }
    else if ( ISTVI(tt_type) ) {
        for ( i=0; i<15 ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  tvif%-3d = \\{%d}%s\n",i+1,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  tvif%-3d = %s\n",i+1,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
        for ( i=16; i<31 ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  tvisf%-3d = \\{%d}%s\n",i+1-16,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  tvisf%-3d = %s\n",i+1-16,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
        for ( i=32; i<67 ; i++ ) {
            char * s = "" ;
            switch ( i ) {
            case 32: s = "tvibs"        ; break ;
            case 33: s = "tviclrln"     ; break ;
            case 34: s = "tvisclrln"    ; break ;
            case 35: s = "tviclrpg"     ; break ;
            case 36: s = "tvisclrpg"    ; break ;
            case 37: s = "tvidelchar"   ; break ;
            case 38: s = "tvidelln"     ; break ;
            case 39: s = "tvienter"     ; break ;
            case 40: s = "tviesc"       ; break ;
            case 41: s = "tvihome"      ; break ;
            case 42: s = "tvishome"     ; break ;
            case 43: s = "tviinsert"    ; break ;
            case 44: s = "tviinschar"   ; break ;
            case 45: s = "tviinsln"     ; break ;
            case 46: s = "tvipgnext"    ; break ;
            case 47: s = "tvipgprev"    ; break ;
            case 48: s = "tvireplace"   ; break ;
            case 49: s = "tvireturn"    ; break ;
            case 50: s = "tvitab"       ; break ;
            case 51: s = "tvistab"      ; break ;
            case 52: s = "tviprtscn"    ; break ;
            case 53: s = "tvisesc"       ; break ;
            case 54: s = "tvisbs"        ; break ;
            case 55: s = "tvisenter"     ; break ;
            case 56: s = "tvisreturn"    ; break ;
            case 57: s = "tviuparr"      ; break ;
            case 58: s = "tvidnarr"      ; break ;
            case 59: s = "tvilfarr"      ; break ;
            case 60: s = "tvirtarr"      ; break ;
            case 61: s = "tvisuparr"     ; break ;
            case 62: s = "tvisdnarr"     ; break ;
            case 63: s = "tvislfarr"     ; break ;
            case 64: s = "tvisrtarr"     ; break ;
            case 65: s = "tvisend"       ; break ;
            case 66: s = "tvissend"      ; break ;
            }
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  %s = \\{%d}%s\n",s,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  %s = %s\n",s,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
    }
    else if ( ISDG200(tt_type) ) {
        for ( i=0; i<110 ; i++ ) {
            if ( udkfkeys[i] &&
                 (udkfkeys[i][0] < SP || udkfkeys[i][0] >= 127) )
                printf( "  dgf%-3d = \\{%d}%s\n",i+1,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  dgf%-3d = %s\n",i+1,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
    }
    else if ( ISHP(tt_type) ) {
        for ( i=0; i<=15 ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  hpf%d = \\{%d}%s\n",i+1,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  hpf%d = %s\n",i+1,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
        if ( udkfkeys[16] && udkfkeys[16][0] < SP )
            printf( "  hpbacktab = \\{%d}%s\n",
                    udkfkeys[16][0], &(udkfkeys[16][1]));
        else
            printf( "  hpbacktab = %s\n",
                    udkfkeys[16]?udkfkeys[16]:"(unassigned)");
        if ( udkfkeys[17] && udkfkeys[17][0] < SP )
            printf( "  hpenter = \\{%d}%s\n",
                    udkfkeys[17][0], &(udkfkeys[17][1]));
        else
            printf( "  hpenter = %s\n",
                    udkfkeys[17]?udkfkeys[17]:"(unassigned)");
        if ( udkfkeys[18] && udkfkeys[18][0] < SP )
            printf( "  hpreturn = \\{%d}%s\n",
                    udkfkeys[18][0], &(udkfkeys[18][1]));
        else
            printf( "  hpreturn = %s\n",
                    udkfkeys[18]?udkfkeys[18]:"(unassigned)");

    }
    else if ( ISIBM31(tt_type) ) {
        for ( i=0; i<(K_I31_MAX-K_I31_MIN+1) ; i++ ) {
            if ( udkfkeys[i] && udkfkeys[i][0] < SP )
                printf( "  i31_f%d = \\{%d}%s\n",i+1,
                        udkfkeys[i][0], &(udkfkeys[i][1]));
            else
                printf( "  i31_f%d = %s\n",i+1,
                        udkfkeys[i]?udkfkeys[i]:"(unassigned)");
        }
    }
    printf("\n");
#endif /* NOVKERBS */
}

void
SNI_bitmode(int bits) {
    int i;
    int cs;

    sni_bitmode = bits;
    if ( sni_bitmode == 7 ) {
                /* Load National character set into G0/G1/G2/G3 */
                /* GL to G0, GR to G1                           */
                /* National keyboard is active                  */
                for ( i = 0 ; i < 4 ; i++ ) {
                        G[i].designation = dec_nrc;
                        G[i].size = cs94 ;
                        G[i].c1 = TRUE ;
                        G[i].national = CSisNRC(dec_nrc);
                        G[i].rtoi = xl_u[dec_nrc];
                        if ( ck_isunicode() ) {
                                G[i].itol = NULL ;
                                G[i].ltoi = NULL ;
                        }
            else {
                G[i].itol = xl_tx[tcsl] ;
                G[i].ltoi = xl_u[tcsl] ;
            }
            G[i].itor = xl_tx[dec_nrc];
        }
        GL = &G[0];
        GR = &G[1];
    } else if ( sni_bitmode == 8 ) {
        /* US-ASCII to G0 (GL) */
        /* Brackets to G1      */
        /* Blanks to G2        */
        /* Latin 1 to G3 (GR)  */
        /* Latin 1 keyboard is active */
        for ( i = 0 ; i < 4 ; i++ ) {
            switch ( i ) {
            case 0: cs = TX_ASCII; break;
            case 1: cs = TX_SNIBRACK; break;
            case 2: cs = TX_SNIBLANK; break;
            case 3: cs = TX_8859_1; break;
            default:
                cs = TX_ASCII;
            }

            G[i].designation = cs;
            G[i].size = cs94 ;
            G[i].c1 = TRUE ;
            G[i].national = CSisNRC(cs);
            G[i].rtoi = xl_u[cs];
            if ( ck_isunicode() ) {
                G[i].itol = NULL ;
                G[i].ltoi = NULL ;
            }
            else {
                G[i].itol = xl_tx[tcsl] ;
                G[i].ltoi = xl_u[tcsl] ;
            }
            G[i].itor = xl_tx[cs];
        }
        GL = &G[0];
        GR = &G[3];
    }
}

/*---------------------------------------------------------------------------*/
/* SNI_chcode                                               | Page: View     */
/*---------------------------------------------------------------------------*/
/* *Assumed* this should only affect the View page. I don't have access to an
 * SNI terminal to test with, but I don't think they support the DEC VT paging
 * escape sequences */
void
SNI_chcode( int state ) {
    int    x,y;
    USHORT w,h;
    USHORT ch;

    if ( sni_bitmode == 7 ) {
        if (!sni_chcode_7 || sni_chcode == state)
            return;

        sni_chcode = state;
        if ( sni_chcode ) {
            /* if the current National language is German then convert */
            /* NRC characters to US-ASCII characters in the current    */
            /* screen.
            */
            if ( G[0].designation == TX_GERMAN ) {
                w = VscrnGetWidth(VTERM);
                h = VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0);
                for (y = 0; y < h; y++) {
                    for ( x = 0 ; x < w; x++ ) {
                        ch = VscrnGetCell( VTERM, x, y, TRUE )->c;
                        if ( !ck_isunicode() )
                            ch = xl_u[tcsl](ch);
                        switch ( ch ) {
                        case 0xA7: ch = '@'; break;
                        case 0xC4: ch = '['; break;
                        case 0xD6: ch = '\\'; break;
                        case 0xDC: ch = ']'; break;
                        case 0xE4: ch = '{'; break;
                        case 0xF6: ch = '|'; break;
                        case 0xFC: ch = '}'; break;
                        case 0xDF: ch = '~'; break;
                        default:
                            continue;
                        }
                        VscrnGetCell( VTERM, x, y, TRUE )->c = ch;
                    }
                }
                for ( x = 0 ; x < w; x++ ) {
                    ch = VscrnGetCell( VSTATUS, x, 0, TRUE )->c;
                    if ( !ck_isunicode() )
                        ch = xl_u[tcsl](ch);
                    switch ( ch ) {
                    case 0xA7: ch = '@'; break;
                    case 0xC4: ch = '['; break;
                    case 0xD6: ch = '\\'; break;
                    case 0xDC: ch = ']'; break;
                    case 0xE4: ch = '{'; break;
                    case 0xF6: ch = '|'; break;
                    case 0xFC: ch = '}'; break;
                    case 0xDF: ch = '~'; break;
                    default:
                        continue;
                    }
                    VscrnGetCell( VSTATUS, x, 0, TRUE )->c = ch;
                }
                VscrnIsDirty(VTERM);
            }
        } else {
            /* if the current National language is German then convert */
            /* US-ASCII characters to NRC characters in the current    */
            /* screen.                                                 */
            if ( G[0].designation == TX_GERMAN ) {
                w = VscrnGetWidth(VTERM);
                h = VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0);
                for (y = 0; y < h; y++) {
                    for ( x = 0 ; x < w; x++ ) {
                        ch = VscrnGetCell( VTERM, x, y, TRUE )->c;
                        if ( !ck_isunicode() )
                            ch = xl_u[tcsl](ch);
                        switch ( ch ) {
                        case '@': ch = 0xA7; break;
                        case '[': ch = 0xC4; break;
                        case '\\': ch = 0xD6; break;
                        case ']': ch = 0xDC; break;
                        case '{': ch = 0xE4; break;
                        case '|': ch = 0xF6; break;
                        case '}': ch = 0xFC; break;
                        case '~': ch = 0xDF; break;
                        default:
                            continue;
                        }
                        if ( !ck_isunicode() ) {
                            ch = xl_tx[tcsl](ch);
                        }
                        VscrnGetCell( VTERM, x, y, TRUE )->c = ch;
                    }
                }
                for ( x = 0 ; x < w; x++ ) {
                    ch = VscrnGetCell( VSTATUS, x, 0, TRUE )->c;
                    if ( !ck_isunicode() )
                        ch = xl_u[tcsl](ch);
                    switch ( ch ) {
                    case '@': ch = 0xA7; break;
                    case '[': ch = 0xC4; break;
                    case '\\': ch = 0xD6; break;
                    case ']': ch = 0xDC; break;
                    case '{': ch = 0xE4; break;
                    case '|': ch = 0xF6; break;
                    case '}': ch = 0xFC; break;
                    case '~': ch = 0xDF; break;
                    default:
                        continue;
                    }
                    if ( !ck_isunicode() ) {
                        ch = xl_tx[tcsl](ch);
                    }
                    VscrnGetCell( VSTATUS, x, 0, TRUE )->c = ch;
                }
                VscrnIsDirty(VTERM);
            }
        }
    } else if ( sni_bitmode == 8 ) {
        if (!sni_chcode_8)
            return;

        sni_chcode = state;
    }
}


/* Home the cursor taking DECSASD and DECOM into account. This is really for
 * VT-like emulations - for others that don't have margins, just use
 * lgotoxy(vmode,1,1) instead.
 */
void
home_cursor(int vmode)
{
    if ( decsasd == SASD_STATUS || !relcursor)
    {
        /* The VT520 doesn't seem to implement DECLRMM (left/right margins) on
         * its status line, and it only has the one status line so no DECSTBM
         * too, meaning that on the status line home is always 1,1.
         */
        lgotoxy( decsasd == SASD_STATUS ? VSTATUS : VTERM, 1, 1 );
    }
    else  /* relcursor */
    {
        /* If DECOM is set, send the cursor to the top
         * left corner within the page margins */
        lgotoxy(VTERM,
            vscrn_c_page_margin_left(VTERM),
            vscrn_c_page_margin_top(VTERM));
    }
}

/* Returns the right margin that is currently in effect given the cursors
 * current location.
 *
 * For DEC terminals this depends on if the cursor is within the scroll region
 * or not and, for models supporting left and right margins, if it is already
 * past the right margin or not.
 *
 * Double-width lines are also taken into account.
 */
int
cursor_right_margin(int vmode)
{
    /* Normally the right margin is the right edge of the screen */
    int rmargin = VscrnGetWidth(vmode);

    /* Double-width lines halve the length of the line. As double-width lines
     * are cleared and disabled on entering DECLRMM, if we encounter one then
     * we know that DECLRMM is disabled so no need to go any further. */
    if (isdoublewidth(wherey[vmode])) return rmargin / 2;

    /* But if we're within the scroll region on a terminal that supports setting
     * the right margin, then its the set right margin. For all terminals that
     * *don't* support setting the right margin, the right margin will always be
     * set to the right edge of the screen so no need to check term type.
     */
    if (wherey[vmode] >= vscrn_c_page_margin_top(vmode) &&
        wherey[vmode] <= vscrn_c_page_margin_bot(vmode) &&
        wherex[vmode] <= vscrn_c_page_margin_right(vmode)) {
        rmargin = vscrn_c_page_margin_right(vmode);
    }

    return rmargin;
}

/* Returns true if the cursor is currently within the margins.  */
bool
cursor_in_margins(int vmode) {
    if (wherey[vmode] >= vscrn_c_page_margin_top(vmode) &&
        wherey[vmode] <= vscrn_c_page_margin_bot(vmode) &&
        wherex[vmode] >= vscrn_c_page_margin_left(vmode) &&
        wherex[vmode] <= vscrn_c_page_margin_right(vmode)) {
        return TRUE;
    }
    return FALSE;
}

/* Returns the left margin that is currently in effect at the specfied
 * coordinates.
 *
 * For DEC terminals this depends on if the cursor is within
 * the scroll region or not.
 */
int
cursor_pos_left_margin(int vmode, int y, int x)
{
    /* If relcursor is on, then the cursor is constrained to the margins. So the
     * position of the cursor is irrelevant. Otherwise, the position of the left
     * margin only matters if the cursor is within the margins. */
    if (relcursor || cursor_in_margins(vmode)) {
        return vscrn_c_page_margin_left(vmode);
    }

    return 1;
}

/* Returns the left margin that is currently in effect given the cursors
 * current location.
 *
 * For DEC terminals this depends on if the cursor is within
 * the scroll region or not.
 */
int
cursor_left_margin(int vmode)
{
    return cursor_pos_left_margin(vmode, wherey[vmode], wherex[vmode]);
}

void
savecurpos(int vmode, int x) {          /* x: 0 = cursor X/Y only, 1 = all */
    int i ;
    int slot = vmode;

    if (vmode == VTERM
            && ISK95(tt_type)
            && vscrn[vmode].cursor.p == ALTERNATE_BUFFER_PAGE(vmode)) {
        /* We're on the xterm alternate screen - store the cursor in the
         * special alternate screen slot */
        slot = XT_ALTBUF_CURSOR_SLOT;
    }

    saved[slot] = TRUE;                        /* Remember they are saved */
    savedrow[slot] = wherey[vmode];            /* Current row (absolute) */
    savedcol[slot] = wherex[vmode];            /* Current column (absolute) */

    if (x) {
        savedpage[slot] = vscrn[vmode].cursor.p;   /* Current page */
        savedattribute[slot] = attribute;      /* Current PC video attributes */
        saveddefaultattribute[slot] = defaultattribute ;
        savedunderlineattribute[slot] = underlineattribute;
        saveditalicattribute[slot] = italicattribute;
        savedreverseattribute[slot]= reverseattribute;
        savedgraphicattribute[slot]= graphicattribute;
        savedborderattribute[slot]= borderattribute;
        savedblinkattribute[slot]= blinkattribute;
        savedboldattribute[slot] = boldattribute;
		saveddimattribute[slot] = dimattribute;
        savedcrossedoutattribute[slot] = crossedoutattribute;
        savedattrib[slot] = attrib;            /* Current DEC character attributes */
        saverelcursor[slot] = relcursor;       /* Cursor addressing mode */
        savedwrap[slot]     = tt_wrap;         /* Wrap mode */
        savedlcf[slot] = wrapit;    /* Last column flag */

        if ( x==1 ) {
            for (i=0; i<4; i++)
                savedG[slot][i] = G[i] ;
            savedGL[slot] = GL ;
            savedGR[slot] = GR ;
            savedSSGL[slot] = SSGL ;
        }
    }
}

void
restorecurpos(int vmode, int x) {
    int i ;
    int slot = vmode;

    if (vmode == VTERM
            && ISK95(tt_type)
            && vscrn[vmode].cursor.p == ALTERNATE_BUFFER_PAGE(vmode)) {
        /* We're on the xterm alternate screen - restore the cursor from the
         * special alternate screen slot */
        slot = XT_ALTBUF_CURSOR_SLOT;
    }

    if (saved[slot] == FALSE) {                /* Nothing saved, home the cursor */
        home_cursor(vmode);
    }
    else {
        lgotoxy(vmode, savedcol[slot], savedrow[slot]);/* Goto saved position */

        if (x) {
            /* The Xterm alternate screen doesn't participate in the multi-page
             * stuff, so saving and restoring the cursor shouldn't result in
             * switching pages */
            if (slot != XT_ALTBUF_CURSOR_SLOT) {
                switch_to_page(vmode, savedpage[slot], vscrn[vmode].page_cursor_coupling);
            }

            attribute = savedattribute[slot];  /* Restore saved attributes */
            defaultattribute=saveddefaultattribute[slot];
            underlineattribute=savedunderlineattribute[slot];
            italicattribute=saveditalicattribute[slot];
            reverseattribute=savedreverseattribute[slot];
            graphicattribute=savedgraphicattribute[slot];
            borderattribute=savedborderattribute[slot];
            blinkattribute=savedblinkattribute[slot];
            boldattribute=savedboldattribute[slot];
			dimattribute=saveddimattribute[slot];
            crossedoutattribute=savedcrossedoutattribute[slot];
            attrib = savedattrib[slot];
            relcursor = saverelcursor[slot];   /* Restore cursor addressing mode */

            /* TODO: This is proabably for switching in and out of the status
             * line. Current behaviour is wrong. Status line needs a separate
             * saved cursor slot, and tt_wrap among other things should only be
             * saved/restored when switching in and out of the status line. */
            tt_wrap = savedwrap[slot] ;       /* Restore wrap mode */

            if (tt_type != TT_VT100 && tt_type != TT_VT102) {
                /* The VT10x does not save the last column flag, the rest do */
                wrapit = savedlcf[slot];
            }

            if ( x==1 ) {                       /* Restore char sets */
                for (i=0; i<4; i++)
                    G[i] = savedG[slot][i] ;
                GL = savedGL[slot] ;
                GR = savedGR[slot] ;
                SSGL = savedSSGL[slot] ;
            }
        }
    }
}

/* DECSASD - Select Active Status Display */
void
setdecsasd( bool x )
{
    if ( x == SASD_STATUS && decssdt == SSDT_HOST_WRITABLE ) {
        if ( decsasd == SASD_TERMINAL ) {
            savecurpos(VTERM,2);
            if ( saved[VSTATUS] )
                restorecurpos(VSTATUS,2);
        }
        decsasd = x ;
    }
    else if (x == SASD_TERMINAL) {
        if ( decsasd == SASD_STATUS ) {
            savecurpos(VSTATUS,2);
            if ( saved[VTERM] )
                restorecurpos(VTERM,2);
        }
        decsasd = 0 ;
    }
}

/* DECSSDT - Select Status Display Type */
void
setdecssdt( int x )
{
    int i;
    switch ( x ) {
    case SSDT_BLANK:
        settermstatus(FALSE);
        break;
    case SSDT_INDICATOR:
        settermstatus(TRUE);
        break;
    case SSDT_HOST_WRITABLE:
        if ( decssdt == SSDT_INDICATOR ) {
            lgotoxy(VSTATUS,1,1);
            clrtoeoln(VSTATUS,SP);
            savecurpos(VSTATUS,2);
            for ( i=0;i<MAXTERMCOL;i++ )
                hoststatusline[i] = SP ;
            hoststatusline[MAXTERMCOL]=NUL;
        }
        settermstatus(TRUE);
        break;
    }
    decssdt = x ;
    VscrnIsDirty(VTERM);
}

void
setkeyclick(int on)
{
    keyclick = on;
#ifdef KUI
    KuiSetProperty(KUI_TERM_KEYCLICK, on, 0);
#endif /* KUI */
}

void                                    /* Reset the terminal emulator */
doreset(int x) {                        /* x = 0 (soft), nonzero (hard) */
    extern BYTE vmode ;
    extern int dgunix, dgunix_usr;
    int i;

    debug(F111,"doreset","x",x);

	/* Halt any executing macros */
	vt_macro_reset();
	if (x) {
		if (vt_macro_invocation) {
			/* Not safe to wipe macros here just in case one is in the middle of
		 	* executing. Setting this will cause all macros to be wiped later. */
			vt_macro_hard_reset = TRUE;
		} else {
			vt_macro_clear();
		}
	}

    /* And any playing sounds */
    sound_playing = FALSE;

    tt_type_mode = tt_type ;

    decstglt = DECSTGLT_COLOR;
    colorpalette = savedcolorpalette;
    reset_decatc_assignments();

    attribute = defaultattribute = colornormal; /* Normal colors */
    underlineattribute = colorunderline ;
    reverseattribute = colorreverse;
    graphicattribute = colorgraphic;
    borderattribute  = colorborder;
    italicattribute  = coloritalic;
    blinkattribute   = colorblink;
    boldattribute    = colorbold;
	dimattribute     = colordim;
    crossedoutattribute = colorcrossedout;

    saveddefaultattribute[VTERM] = colornormal; /* Default saved values */
    savedunderlineattribute[VTERM] = colorunderline ;
    saveditalicattribute[VTERM] = coloritalic;
    savedreverseattribute[VTERM] = colorreverse;
    savedgraphicattribute[VTERM] = colorgraphic;
    savedborderattribute[VTERM]  = colorborder;
    savedblinkattribute[VTERM] = colorblink;
    savedboldattribute[VTERM]  = colorbold;
	saveddimattribute[VTERM] = colordim;
    savedcrossedoutattribute[VTERM] = colorcrossedout;
    savedattribute[VTERM] = attribute;
	use_bold_attr = bold_is_color;
	use_blink_attr = blink_is_color;

    /* TODO: For xterm, this should default to false */
    colorAttPriority = TRUE;

	truereverse = savedtruereverse;
	trueunderline = savedtrueunderline;
	truedim = savedtruedim;
	truebold = savedtruebold ;
	trueitalic = savedtrueitalic;
    truecrossedout = savedtruecrossedout;
	trueblink = savedtrueblink;

	/* Reset select color in case it was changed by OSC-17/OSC-19 */
	colorselect = savedcolorselect;
	colorcursor = savedcolorcursor;

    /* Reset screen roll keys */
    tt_rkeys[VTERM] = tt_rkeys_saved[VTERM];

    /* Reset the color palettes */
    reset_palettes();

    attrib.blinking = FALSE;            /* No blink */
    attrib.bold = FALSE;                /* No bold */
    attrib.invisible = FALSE;           /* Visible */
    attrib.underlined = FALSE;          /* No underline */
    attrib.reversed = FALSE;            /* No reverse video */
    attrib.unerasable = FALSE;          /* Erasable */
    attrib.graphic = FALSE ;            /* Not graphic character */
    attrib.dim = FALSE ;                /* No dim */
    attrib.wyseattr = FALSE ;
    attrib.italic = FALSE;              /* No italic */
	attrib.crossedout = FALSE;			/* No crossedout */
    attrib.hyperlink = FALSE;
    attrib.linkid = 0;
    savedattrib[VTERM] = attrib;

#ifdef KUI
    tt_bell_flash = user_bell_flash;    /* Urgency on bell back to user setting */
    tt_bell_raise = FALSE;              /* Raise window on bell back to user setting */
    tt_sync_output = FALSE;             /* Synchronized output off */
#endif /* KUI */
    bracketed_paste[VTERM] = FALSE;     /* Bracketed paste off */

    erasemode = user_erasemode;

    decncsm = decncsm_usr;
    decscpp_resize = FALSE;

#ifdef KUI
    /* Erase DRCS font buffers, but only on hard reset*/
    if (x) {
        int i, j;
        EnterDRCSBufferCriticalSection();
        for (i = 0; i < DRCS_BUFFERS; i++) {
            if (drcsbuf[i] != NULL) {
                drcs_t *buf = drcsbuf[i];
                drcsbuf[i] = NULL;
                for (j = 0; j < DRCS_RENDITIONS_TOTAL; j++) {
                    free(buf->renditions[j]);
                }
                free(buf);
            }
        }
        LeaveDRCSBufferCriticalSection();

        /* Restore number of available font buffers for VT520 only on hard reset
         * only */
        decdlda = 2;
    }
#endif /* KUI */

    /* Restore DEC VT Graphic Set translation functions */
    for ( i = 0 ; i < 4 ; i++ )
    {
        G[i].designation = G[i].def_designation ;
        G[i].size = G[i].def_size ;
        G[i].c1 = G[i].def_c1 ;
        G[i].national = CSisNRC(G[i].designation) ;
        if ( tcs_transp ) {
            debug(F111,"doreset - ERROR","G(i).designation == TX_TRANSP",i);
            G[i].rtoi = NULL ;
            G[i].itol = NULL ;
            G[i].ltoi = NULL ;
            G[i].itor = NULL ;
        }
        else
        {
            G[i].rtoi = xl_u[G[i].designation];
            G[i].itol = xl_tx[tcsl] ;
            G[i].ltoi = xl_u[tcsl] ;
            G[i].itor = xl_tx[G[i].designation];
        }
        G[i].init = FALSE ;
    }
    GNOW = GL = &G[0] ;
    GR = ISLINUX(tt_type_mode) ? &G[1] : ISVT220(tt_type_mode) ? &G[2] : &G[1];
    SSGL = NULL ;
    decnrcm = decnrcm_usr;
    setdecsasd(SASD_TERMINAL);
    if ( IS97801(tt_type_mode) )
        setdecssdt( SSDT_HOST_WRITABLE );
    else if ( x )
        setdecssdt( tt_status_usr[VTERM] ? SSDT_INDICATOR : SSDT_BLANK );

    xprint = FALSE ;                    /* Turn off ctrl print */
    setaprint(FALSE);                   /* Turn off auto print */
    cprint = FALSE ;                    /* Turn off copy print */
    if ( !uprint ) {
        printeroff() ;                  /* Turn off the printer if it is on */
        printon = FALSE;                /* Printer is not on */
    }
    printregion = FALSE;                /* Printer extent is full screen */
    screenon = TRUE;                    /* The screen is turned on */
#ifdef CK_APC
    if ( !apcactive ) {
        apcactive = APC_INACTIVE;       /* An APC command is not active */
        apclength = 0;                  /* ... */
    }
    apcrecv = dcsrecv = oscrecv = pmrecv = pu1recv = pu2recv = c1strrecv = 0 ;
#endif /* CK_APC */

    vt52graphics = FALSE;               /* Get out of VT52 graphics mode */
    for ( i=0;i<VNUM;i++ )
        saved[i] = FALSE;               /* Nothing is saved */
    tnlm = tt_crd = FALSE;              /* We're not in newline mode */
    insertmode = FALSE;                 /* Not in character-insert mode */
    tt_arrow = TTK_NORM;                /* Arrow keypad to cursor mode */
    tt_keypad = TTK_NORM;               /* Auxilliary keypad to numeric mode */
    tt_shift_keypad = FALSE ;           /* Do not shift keypad values */
#ifdef NT
    tt_autorepeat = TRUE;               /* Keyboard autorepeat ON */
#endif /* NT */
    tt_wrap = TRUE;                     /* (FALSE for real VT terminal!) */
    tt_bell = tt_bell_usr;
    send_c1 = send_c1_usr;              /* Don't send C1 controls */
    keylock = FALSE;                    /* Keyboard is not locked */

    /* Reset paging */
    from_alternate_buffer(VTERM);
    vscrn[VTERM].page_cursor_coupling = TRUE;
    switch_to_page(VTERM, 0, TRUE);
	saved_view_page = -1;
    saved_cursor_page = -1;
	tt_term_scroll = 1;
    decspma_max_page = -1;

    udkreset() ;                        /* Reset UDKs     */
    deccolm = FALSE;                    /* default column mode */
    tt_cols[VTERM] = tt_cols_usr ;
#ifdef KUI
    scrollmode = tt_scrollmode;      /* set terminal scroll mode to original */
    smooth_speed = tt_smooth_speed;
#else
    if (tt_updmode == TTU_FAST ) /* set terminal scroll mode to original */
        JumpScroll();
    else
        SmoothScroll();
#endif /* KUI */
    if (vmode==VTERM)
        SetCols(VTERM) ;
    naws();
    ipadl25();

    decsace = FALSE;
    decscnm = FALSE;
    if (decscnm_usr)                    /* Reverse Screen Mode */
        flipscreen(VTERM);

    for (i = 1; i < VscrnGetWidth(VTERM); i++)  /* Tab settings every 8 spaces except QNX */
      htab[i] = (i % (ISQNX(tt_type_mode)?4:8)) == 1 ? 'T' : '0'; /* was "== 0" */
    relcursor = FALSE;                  /* Cursor position is absolute */

    /* Real terminal sets margins to (1,24) */
	for (i = 0; i < vscrn[VTERM].page_count; i++) {
		set_page_margins(i, 1, VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0),
							1, VscrnGetWidth(VTERM));
	}

    escstate = ES_NORMAL;               /* In case we're stuck in a string */
    setborder();                        /* Restore border color */

    if (x) {                            /* Now clear the screen and home the cursor*/
        if ( VscrnGetBufferSize(VTERM,TRUE,TRUE) > 0 ) {
            int p;
			for (p = 0; p < vscrn[VTERM].page_count; p++) {
				if ( !VscrnIsClear(VTERM, p)) {
            		clrpage(VTERM,SP,p);
				}
#ifdef KUI
			    /* Erase ruled lines - these are normally perserved when the
			     * screen is cleared */
			    decerlbra_escape(1, 1, tt_cols[VTERM], tt_rows[VTERM]);
#endif /* KUI */
			}
			lgotoxy(VTERM,1,1);       /* and home the cursor */
        }
    }
    VscrnSetDisplayHeight(VTERM,0);
    if (scrollflag[VTERM])              /* Were we rolled back? */
      scrollflag[VTERM] = 0;            /* Not any more ... */
    ipadl25();                          /* Put back regular status line */

    cursorena[VTERM] = tt_cursorena_usr;/* Cursor enabled? */
    cursoron[VTERM] = FALSE ;           /* Force newcursor to restore the cursor */
    tt_cursor = tt_cursor_usr ;
    setcursormode() ;

    if ( duplex_sav > -1 ) {            /* Restore user Echo setting */
        duplex = duplex_sav ;
        duplex_sav = -1 ;
    }
    deckbum = FALSE ;                   /* Keyboard in Typewriter mode */
    if ( savdecbkm )                    /* Restore Backspace mode to user default */
    {
        keymap[KEY_SCAN | 8] = savdecbkm ;
        savdecbkm = 0 ;
    }

    sco8bit = FALSE ;                   /* SCO ANSI 8th bit quoting off */
    scoBCS2 = FALSE ;                   /* SCO ANSI BCS2 mode */
    wyse8bit = FALSE ;
    crm = FALSE ;                       /* SCO ANSI c0 display off      */
    setkeyclick(FALSE);

    marginbell = FALSE ;
    marginbellcol = VscrnGetWidth(VTERM)-8 ;

    beepfreq = DEF_BEEP_FREQ ;
    beeptime = DEF_BEEP_TIME ;

    sni_pagemode = sni_pagemode_usr;    /* SNI 97801 AutoRoll */
    sni_scroll_mode = sni_scroll_mode_usr;/* SNI 97801 Roll */
    if ( IS97801(tt_type_mode) ) {
        SNI_chcode(sni_chcode_usr);     /* 97801 CH.CODE mode */
        sni_chcode_7 = TRUE;            /* 97801 CH.CODE key enabled 7-bit mode */
        sni_chcode_8 = TRUE;            /* 97801 CH.CODE key enabled 8-bit mode */
        SNI_bitmode((cmask == 0377) ? 8 : 7);
    }

    autoscroll = TRUE ;                 /* WYSE ASCII AutoScroll */
    protect = FALSE;                    /* WYSE ASCII Protect */
    writeprotect = FALSE ;              /* WYSE ASCII WriteProtect */
    WPattrib = defWPattrib;             /* WYSE ASCII WP Attribute */
    wysegraphics = FALSE ;
    wy_keymode = FALSE ;                /* WYSE ASCII Key Appl Mode */
    wy_enhanced = TRUE ;                /* WYSE ASCII Enhanced Mode On */
    wy_widthclr = FALSE ;               /* WYSE ASCII Width Clear Mode Off */
    wy_nullsuppress = TRUE;             /* WYSE ASCII Null Suppress On */
    if ( ISWYSE(tt_type_mode) ||
         ISTVI(tt_type_mode) ||
         ISHZL(tt_type_mode) ||
         ISDG200(tt_type_mode) ) {      /* WYSE ASCII Auto Page Mode */
        wy_autopage = TRUE;
    }
    else {
        wy_autopage = FALSE ;
    }
    if ( wy_monitor ) {                 /* WYSE ASCII Monitor Mode */
        setdebses(FALSE);
        wy_monitor = FALSE ;
    }
    hzgraphics = 0;                     /* Hazeltine Graphics Mode */

    switch ( tt_type_mode ) {           /* Do Attributes occupy a space in */
    case TT_WY30:                       /* LINE or PAGE modes              */
    case TT_WY50:
    case TT_TVI910:
    case TT_TVI925:
    case TT_TVI950:
        tt_hidattr = FALSE;
        break;
    case TT_HP2621:
    case TT_HPTERM:
    default:
        tt_hidattr = TRUE ;
        break;
    }

    if ( ISWY60(tt_type_mode) )         /* Set the proper Attribute Mode */
        attrmode = ATTR_PAGE_MODE | ATTR_CHAR_MODE ;
    else if ( ISWYSE(tt_type_mode) || ISTVI(tt_type_mode) )
        attrmode = ATTR_PAGE_MODE ;
    else if ( ISHP(tt_type_mode) )
        attrmode = ATTR_LINE_MODE ;
    else
        attrmode = ATTR_CHAR_MODE ;

    tt_kb_mode = KBM_EN ;               /* Turn off Special Keyboard Modes */

    tvi_ic = SP ;                       /* TVI Insert Char is space */
    wy_block = FALSE;                  /* TVI in Conversation mode */

    dgunix = dgunix_usr;

    Qsaved = FALSE;                     /* QANSI Saved Character sets */

    ba80_fkey_read = 0;                 /* We are not reading BA80 fkeys */
    vtnt_index = 0;
    vtnt_read  = VTNT_MIN_READ;

#ifdef KUI
    transmit_focus_change = FALSE;      /* Disable focus events */
#endif /* KUI */

    /* Disable y active mouse reporting modes */
#ifdef OS2MOUSE
    mouse_reporting_mode &= ~(MOUSEREPORTING_ACTIVE | MOUSEREPORTING_UNSUPPORTED);
#endif /* OS2MOUSE */

    dokverb(VTERM,K_ENDSCN);
    dokverb(VTERM,K_MARK_CANCEL);

#ifdef CKLEARN
    learnreset();
#endif /* CKLEARN */

    VscrnIsDirty(VTERM) ;
}

/* Stops macro execution and resets all state ready for a new invocation */
void vt_macro_reset() {
	vt_macro_invocation = FALSE;
	memset(vt_macro_stack, -1, MACRO_STACK_SIZE);
	memset(vt_macro_position, -1, MACRO_STACK_SIZE);
	vt_macro_sp = -1;
	vt_macro_call_depth = -1;
}

/* Stops macro execution and clears all macro space */
void vt_macro_clear() {
	int i;

	vt_macro_reset();
	vt_macro_hard_reset = FALSE;
	vt_macro_size=0;

	/* Clear *all* macro definitions */
	for (i = 0; i < 64; i++) {
		if (vt_macro_definitions[i]) {
			free(vt_macro_definitions[i]);
			vt_macro_definitions[i] = NULL;
		}
	}
}

/* Function: DECINVM */
void vt_invoke_macro(char macro_id) {
	if (macro_id < 0 || macro_id > 63) return;

	/* If we aren't already processing a macro, start from
	 * the bottom of the stack */
	if (!vt_macro_invocation) vt_macro_reset();

	/* Macro must exist */
	if (vt_macro_definitions[macro_id] == NULL) return;

	if (ISVT520(tt_type_mode) && vt_macro_invocation) {
		/* While the VT520 is limited to macros nested 16
		 * levels deep, it implements a kind of tail call
		 * optimisation. If the final action of a macro is
		 * to invoke another macro, the invoked macro reuses
		 * the calling macros position on the stack allowing
		 * for recursion deeper than 16 levels. This has
		 * been observed in VT520 v2.1 and may be new to the
		 * VT520 in general - the VT420 apparently doesn't
		 * have this behaviour, though I don't own one to
		 * confirm this myself.
		 *
		 * Using this mechanism it is possible to put the
		 * VT520 v2.1 into an infinite loop. Resetting the
		 * terminal from the setup menu gets out of it, but
		 * we don't want to allow that here so K95 keeps
		 * track of the call depth and aborts if it goes on
		 * too long.
		 */
		int mac_id = vt_macro_stack[vt_macro_sp];
		char* macro = vt_macro_definitions[mac_id];
		int pos = vt_macro_position[vt_macro_sp];
		if (macro[pos+1] == '\0') {
			if (vt_macro_call_depth <= MACRO_CALL_DEPTH_LIMIT) {
				vt_macro_sp -= 1;
				vt_macro_call_depth += 1;
			} else {
				debug(F101, "DECINVM - call depth limit", "", vt_macro_call_depth);
			}
		}
	}

	/* Increment stack pointer */
	vt_macro_sp += 1;

	/* Macros can only be called 16 levels deep */
	if (vt_macro_sp >= MACRO_STACK_SIZE) {
		debug(F100, "DECINVM - stack limit", "", 0);
		vt_macro_sp = MACRO_STACK_SIZE - 1;
		return;
	}

	vt_macro_stack[vt_macro_sp] = macro_id;
	vt_macro_position[vt_macro_sp] = -1;
	vt_macro_invocation = TRUE;
}

/* Gets the next character from the currently executing macro (if any). Will
 * also clear all macro space if it has been asked to do so by doreset() */
int vt_macro_in() {
	int id, pos, c;
	char* macro = NULL;

	if (vt_macro_hard_reset) {  /* Set by doreset(1) */
		vt_macro_clear();
	}

	if (!vt_macro_invocation) {
		return -1; /* No macro in progress */
	}

	if (vt_macro_sp < 0) {
		/* Finished processing the macro at the bottom of the stack. All done. */
		vt_macro_reset();
		return -1;
	}

	/* get the current macro */
	pos = vt_macro_position[vt_macro_sp] + 1;
	id = vt_macro_stack[vt_macro_sp];
	macro = vt_macro_definitions[id];

	if (macro == NULL || macro[pos] == '\0') {
		/* Invalid macro, or end of macro. Pop the stack and try again. */
		vt_macro_sp = vt_macro_sp - 1;
		if (vt_macro_call_depth > 0) vt_macro_call_depth = vt_macro_call_depth - 1;
		debug(F100, "DECINVM - vt_macro_in - invalid or end of macro", "", 0);
		return vt_macro_in();
	}

	/* Get the next character and update the current position */
	c = macro[pos];
	vt_macro_position[vt_macro_sp] = pos;

	return c;
}

/*
  The flow of characters from the communication device to the screen is:

                           +---(debug)----+
                           |              |
  rdcomwrtscr --> cwrite --+--> vt100 --> wrtch
                                       |              |
                                       +--> vtescape--+

  rdcomwrtscr() reads character from communication device via ttinc() and:
   - converts 8-bit controls to 7-bit ESC sequences
   - handles TELNET negotiations
   - handles SO/SI (NOTE: this prevents
   - handles charset translation
   - handles newline-mode and cr-display
   - handles connection loss
   - passes all output chars to cwrite()

  cwrite()
   - handles debug output, direct to wrtch().
   - detects and parses escape-sequences:
     . builds up escape sequence in buffer
     . when complete, calls vtescape(), or does APC.
   - when not debugging & not in esc seq, sends all other chars to vt100().

  vt100()
   - handles ctrl chars in straightforward, modeless way (ENQ, tab, BS, beep)
   - *thinks* it handles SO/SI, but never gets called for this (???)
   - handles graphic chars via mode (G[], vtgraphics, etc) -> wrtch()
   - handles wraparound

  vtescape()
   - acts on escape sequences, changes state, moves cursor, etc.
*/

/*
 * RDCOMWRTSCR  --  Read from the communication device and write to the screen.
 * This function is executed by a separate thread.
 */

void
rdcomwrtscr(void * pArgList)
{
    int c=0;
    int prty = -2;
    int prtyboost = 0;

    PostRdComWrtScrThreadSem() ;
    setint();

    while ( !Shutdown )
    {

        /* Close printer if necessary */
        if ( printerclose_t ) {
            if ( printerclose_t < time(NULL) ) {
                printerclose();
            }
        }

        if ( !IsConnectMode() ||
#ifdef COMMENT
             what != W_CONNECT ||
#endif /* COMMENT */
             !term_io ||
             (ttyfd == -1
#ifdef CK_TAPI
               || (!tttapi && ttyfd == -2)
#endif /* CK_TAPI */
               ) &&
             !le_inbuf() ||
             holdscreen ) {
            /* debug(F110,"rdcomwrtscr","Waiting for CONNECT_MODE or HOLDSCREEN",0); */
            if (prty != -1 ) {
                prty = -1;      /* lie */
                SetThreadPrty(XYP_REG,0);
            }
            msleep(500);
            continue;
        }

        if ( priority != prty ) {
#ifdef NT
            SetThreadPrty(priority,isWin95() ? 3 : 11);
#else /* NT */
            SetThreadPrty(priority,3);
#endif /* NT */
            prty = priority;
            prtyboost = 0;
        }

        c = ttinc(-500);           /* Get a character from the host */
        if ( c < 0 ) {
            if ( ttyfd == -1
#ifdef CK_TAPI
                 || (!tttapi && ttyfd == -2)
#endif /* CK_TAPI */
                 ) {
                SetConnectMode(FALSE,CSX_HOSTDISC);
                strcpy(termessage, "Connection closed.\n");
            }
            else if (c == -2)
            {
                SetConnectMode(FALSE,CSX_HOSTDISC);
                strcpy(termessage, "Connection closed.\n");
                ttclos(0) ;
                /* link broken */
            }
            else if (c == -3)
            {
                SetConnectMode(FALSE,CSX_SESSION);
                strcpy(termessage, "Session Limit exceeded - closing connection.\n");
                ttclos(0) ;
                /* link broken */
            }
            else {
                if (prtyboost == 1) {
#ifdef NT
                    SetThreadPrty(priority,isWin95() ? 3 : 11);
#else /* NT */
                    SetThreadPrty(priority,3);
#endif /* NT */
                    prtyboost = 0;
                }
                msleep(0);
            }
            continue;
        }
        else {
            scriptwrtbuf(c);

            if (prtyboost == 0) {
#ifdef NT
                SetThreadPrty(priority,(isWin95() ? 3 : 11)+10);
#else /* NT */
                SetThreadPrty(priority,13);
#endif /* NT */
                prtyboost = 1;
            }
        }

#ifdef __DEBUG
        /* we want to be able to see things on a character */
        /* by character basis when debugging these threads */
        /* msleep(0) ; */
#endif /* __DEBUG */
    }
    PostRdComWrtScrThreadDownSem() ;
    ckThreadEnd(pArgList) ;
}

int
ltorxlat( int c, CHAR ** bytes )
{
    unsigned short xkey, xkey7;
    static CHAR mybyte;
    int count = 1;

    xkey = (unsigned short) c;

    if ( tt_kb_glgr ) {
        if (xkey <= 127)
        {
            if ( txrinfo[tcsl]->size != 94 )
                xkey = (*xl_u[TX_ASCII])(xkey);
            else
            {
                if (GL->ltoi)
                    xkey = (*GL->ltoi)(xkey);
            }
            if ( tt_utf8 ) {
                count = ucs2_to_utf8( key, bytes );
                return(count);
            }
            else if (GL->itor)
                xkey = (*GL->itor)(xkey);
        }
        else
        {
            if ( tt_kb_mode == KBM_HE )
            {
                xkey7 = xkey = xl_u[TX_CP862](xkey);
            }
            else if ( tt_kb_mode == KBM_RU )
            {
                xkey7 = xkey = xl_u[TX_CP866](xkey);
            }
			else if ( tt_kb_mode == KBM_MM )
            {
                xkey7 = xkey = xl_u[TX_CP437](xkey);
            }
            else {
                if (GL->ltoi)
                    xkey7 = (*GL->ltoi)(xkey);
                else
                    xkey7 = 0xFFFF;

                if (GR->ltoi)
                    xkey = (*GR->ltoi)(xkey);
            }

            if ( tt_utf8 ) {
                count = ucs2_to_utf8( xkey, bytes );
                return(count);
            }
            else {
                if ( GL->itor )
                    xkey7 = (*GL->itor)(xkey7);
                else
                    xkey7 = 0xFFFF;

                if ( GR->itor)
                    xkey = (*GR->itor)(xkey);
                else
                    xkey = 0xFFFF;

                if ( xkey7 != 0xFFFF )
                    xkey = xkey7;
            }
        }
    } else {
        /* Use Keyboard Character-set based upon  */
        /* state of DECNRCM for VT terminals or   */
        /* CH.CODE and bit mode for SNI terminals */

        if (xkey > 127) {
            if ( tt_kb_mode == KBM_HE )
            {
                xkey = xl_u[TX_CP862](xkey);
            }
            else if ( tt_kb_mode == KBM_RU )
            {
                xkey = xl_u[TX_CP866](xkey);
            }
			else if ( tt_kb_mode == KBM_MM )
            {
                xkey = xl_u[TX_CP1252](xkey);
            }
            else if ( IS97801(tt_type_mode) ) {
                debug(F111,"ltorxlat()","xkey > 127",xkey);
                debug(F111,"ltorxlat()","tcsl",tcsl);
                xkey = xl_u[tcsl](xkey);
                debug(F111,"ltorxlat()","xl_u[tcsl](xkey)",xkey);
            } else
                xkey = xl_u[tcsl](xkey);
        }

        if ( tt_utf8 ) {
            count = ucs2_to_utf8( xkey, bytes );
            return(count);
        } else if ( ISVT100(tt_type_mode) && decnrcm ||
                    IS97801(tt_type_mode) && sni_bitmode == 7 && !sni_chcode) {
            xkey = xl_tx[dec_nrc](xkey);
            if ( IS97801(tt_type_mode) ) {
                debug(F111,"ltorxlat() sni=7 !ch.code","xl_tx[decnrc]",xkey);
            }
        } else if (IS97801(tt_type_mode) && sni_bitmode == 7 && sni_chcode) {
            if ( IS97801(tt_type_mode) )
                debug(F100,"ltorxlat() sni=7 ch.code","",0);
            if ( xkey > 127 ) {
                bytes = NULL;
                return(0);
            }
            /* otherwise, we use US-ASCII - no translation necessary */
        } else if ( cs_is_nrc(dec_kbd) && xl_tx[dec_kbd] ) {
            xkey = xl_tx[dec_kbd](xkey);
        } else if ( xkey > 127 && xl_tx[dec_kbd] ) {
            xkey = xl_tx[dec_kbd](xkey);
        }
    }
    if ( xkey == 0xFFFF ) {
        debug(F110,"ltorxlat()","xkey == 0xFFFF",0);
        bytes = NULL;
        return(0);
    }

    mybyte = (unsigned char) xkey;
    *bytes = &mybyte;
    return(1);
}

int
utorxlat( int c, CHAR ** bytes )
{
    unsigned short xkey;
    static CHAR mybyte;
    int count = 1;

    xkey = (unsigned short) c;

    if ( tt_kb_glgr ) {
        if ( tt_utf8 ) {
            count = ucs2_to_utf8( key, bytes );
            return(count);
        }
        else if (GL->itor)
            xkey = (*GL->itor)(xkey);
    } else {
        /* Use Keyboard Character-set based upon  */
        /* state of DECNRCM for VT terminals or   */
        /* CH.CODE and bit mode for SNI terminals */

        if ( tt_utf8 ) {
            count = ucs2_to_utf8( xkey, bytes );
            return(count);
        } else if ( ISVT100(tt_type_mode) && decnrcm ||
                    IS97801(tt_type_mode) && sni_bitmode == 7 && !sni_chcode) {
            xkey = xl_tx[dec_nrc](xkey);
            if ( IS97801(tt_type_mode) ) {
                debug(F111,"ltorxlat() sni=7 !ch.code","xl_tx[decnrc]",xkey);
            }
        } else if (IS97801(tt_type_mode) && sni_bitmode == 7 && sni_chcode) {
            if ( IS97801(tt_type_mode) )
                debug(F100,"ltorxlat() sni=7 ch.code","",0);
            if ( xkey > 127 ) {
                bytes = NULL;
                return(0);
            }
            /* otherwise, we use US-ASCII - no translation necessary */
        } else if ( cs_is_nrc(dec_kbd) ) {
            xkey = xl_tx[dec_kbd](xkey);
        } else if ( xkey > 127 ) {
            xkey = xl_tx[dec_kbd](xkey);
        }
    }
    if ( xkey == 0xFFFF ) {
        debug(F110,"ltorxlat()","xkey == 0xFFFF",0);
        bytes = NULL;
        return(0);
    }

    mybyte = (unsigned char) xkey;
    *bytes = &mybyte;
    return(1);
}

int
rtolxlat( int c )
{
    int cx;
    /* Do not perform translations if we are VTNT */
    if ( tcs_transp || ISVTNT(tt_type_mode) )
        return(c);

    debug(F101,"rtolxlat c","",c);
    debug(F101,"rtolxlat tcsl","",tcsl);

    if ( ((ISANSI(tt_type_mode) || ISQANSI(tt_type_mode)) && sco8bit ||
           ISWY60(tt_type_mode) && wyse8bit)
         && c >= 32 )
        c |= 0200 ;             /* Shift 8th bit */

    if ( SSGL == NULL )
        GNOW = c > 127 ? GR : GL ;
    else {
        GNOW = c > 127 ? GR : SSGL ;
        SSGL = NULL ;
    }

    /* SNI 97801 has special translations if CH.CODE is ON */
    if ( IS97801(tt_type_mode) && sni_chcode ) {
        if ( sni_bitmode == 8 && c > 127 ) {
            /* 8-bit mode uses Latin-1 */
            cx = xl_u[TX_8859_1](c);
            if ( !ck_isunicode() )
                cx = xl_tx[tcsl](cx);
            debug(F101,"rtolxlat return 1","",cx);
            return(cx);
        } else if (sni_bitmode == 7 && GNOW == &G[0] ){
            /* 7-bit mode uses dec-nrc */
            cx = xl_u[TX_ASCII](c);
            debug(F101,"rtolxlat return 2","",cx);
            return(cx);
        }
        /* otherwise, perform a normal translation */
    }

    if ( !debses && tcs_transp ) {
        if ( GNOW == GR && !GNOW->national ) {
            c |= 0200;
            literal_ch = TRUE ;
        } else
            c &= ~0200;

        c &= cmdmsk;                        /* Apply command mask. */
    } else {
        if (!debses &&                      /* Not DEBUG mode       */
             c >= 32 &&                     /* Not Control-0 char   */
             !tcs_transp)                   /* Not transparent set */
            c |= 0200;                      /* Shift char to 8-bit  */

        if ( GNOW->national )
            c &= ~0200 ;                    /* Shift to 7-bit */

        c &= cmdmsk;                        /* Apply command mask. */

        /* Translate character sets */
        cx = c ;                    /* Save the old value */
        if ( !(GNOW == GL && c < 32) ) {
            if (GNOW->rtoi)
                c = (*GNOW->rtoi)(c);
            if ( !ck_isunicode() )
            {
                if (GNOW->itol )
                    c = (*GNOW->itol)(c);
            }
#ifdef NT
            else
            {
                if ( win95hsl && c >= 0x23BA && c <= 0x23BD )
                    c = tx_hslsub(c);
                else if ( c >= 0xE000 && c <= 0xF8FF
#ifdef KUI
                          && !(drcsbuf[0] != NULL && IN_DRCS_1_RANGE(c) ||
                               drcsbuf[1] != NULL && IN_DRCS_2_RANGE(c))
#endif /* KUI */
                        ) {
                    /* DRCS soft character sets map into the unicode PUA range,
                     * so don't apply tx_usub to them. */
                    c = tx_usub(c);
                }
                if (win95lucida && c > 0x017f)
                    c = tx_lucidasub(c);
            }
#endif /* NT */
            if ( c < 0 )            /* Character could not be xlated */
                c = '?' ;           /* to local character set */
        }
        if ( cx >= SP && c < SP ||
             c >=128 && c <= 159)
            literal_ch = TRUE ;
        debug(F101,"rtolxlat return 3","",c);
    }
    return(c);
}

int
utolxlat( int c )
{
    c = xl_tx[tcsl](c);
    return(c);
}

/*
  S C R I P T W R T B U F
  This function performs equivalent functionality for [M]INPUT commands
  as RDCOMWRTSCR does for CONNECT sessions.  Must process incoming
  Telnet operations and perform character set translations.

  And since it does exactly the same thing that RDCOMWRTSCR has done for
  years, there is no point in duplicating the code.  So now RDCOMWRTSCR
  calls SCRIPTWRTBUF to do the hard work.
*/
int
scriptwrtbuf(unsigned short word)
/* scriptwrtbuf */ {
    int c, cx, tx;
#ifdef CK_TRIGGER
    extern char * tt_trigger[], * triggerval;
#endif /* CK_TRIGGER */

    /*debug(F111,"scriptwrtbuf","word",word);*/

    /* Close Printer if necessary */
    if ( printerclose_t ) {
        if ( printerclose_t < time(NULL) ) {
            printerclose();
        }
    }

pushed:
    if (f_pushed) {             /* Handle 8-bit controls */
        c = c_pushed;           /* by converting to ESC + 7-bit char */
        f_pushed = 0;
        f_popped = 1;
    }
    else
    {
        c = word;               /* Get a character from the host */

#ifdef TNCODE
        /* Handle TELNET negotiations here */
        if (network && IS_TELNET()) {
            static int got_cr = 0;
            switch ( c ) {
            case IAC:
                if ((tx = tn_doop((CHAR)(c & 0xff),duplex,netinc)) == 0) {
                    return(0);
                }
                else if (tx == -1) {    /* I/O error */
                    strcpy(termessage, "TELNET negotiation error.\n");
                    SetConnectMode(FALSE,CSX_TN_ERR);      /* Quit */
                    return(-1);
                }
                else if (tx == -2) { /* Connection failed. */
                    extern int ttyfd ;
                    SetConnectMode(FALSE,CSX_HOSTDISC);
                    strcpy(termessage, "Connection closed by peer.\n");
                    ttclos(0) ;
                    return(-2);
                }
                else if (tx == -3) { /* Connection failed. */
                    extern int ttyfd ;
                    SetConnectMode(FALSE,CSX_TN_POL);
                    strcpy(termessage, "Connection closed due to telnet policy.\n");
                    ttclos(0) ;
                    return(-2);
                }
                else if (tx == 1) {     /* ECHO change */
                    duplex = 1; /* Get next char */
                    return(1);
                }
                else if (tx == 2) {     /* ECHO change */
                    duplex = 0; /* Get next char */
                    return(2);
                }
                else if (tx == 3) {     /* Quoted IAC */
                    c = 255;    /* proceeed with it. */
                }
#ifdef IKS_OPTION
                else if (tx == 4) {     /* IKS State Change */
                    if ( TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
                         !tcp_incoming) {
                        SetConnectMode(FALSE,CSX_IKSD);
                    }
                    return(4);
                }
#endif /* IKS_OPTION */
                else if (tx == 6) {
                    strcpy(termessage, "Remote Logout.\n");
                    SetConnectMode(FALSE,CSX_HOSTDISC);      /* Quit */
                    return(6);
                }
                else return(0); /* Unknown, get next char */
                break;
            case CK_CR:
                got_cr = 1;
                break;
            case NUL:
                if ( !TELOPT_U(TELOPT_BINARY) && got_cr ) {
                    got_cr = 0;
                    return(0);
                }
            default:
                got_cr = 0;
            }
            if (IsConnectMode() &&
                TELOPT_ME(TELOPT_ECHO) && tn_rem_echo) { /* I'm echo'ing incoming data */
                ttoc(c);
            }
        }
#endif /* TNCODE */

        /* Output to the session log */
        /* The session log should be a pure log of what the host */
        /* is sending minus the Telnet stuff.  This way the file */
        /* can be used as an input stream to the emulator for    */
        /* testing bugs.  This can't happen if we perform C1 to  */
        /* ESC C0 and Character-set conversions.                 */
        if (seslog)
            logchar((USHORT)c);

        /* The purpose of copy-print is to allow K95 to display */
        /* the terminal output on the K95 screen while at the   */
        /* same time piping the raw data through a terminal     */
        /* hooked to the printer device (possibly in bi-di mode */
        /* so we print the raw character here and make cprint   */
        /* supercede the xprint flag.                           */
        /* If the terminal type is Wyse don't print the DC4     */
        /* which is going to result in cprint being turned off. */
        if (cprint && !(ISWYSE(tt_type_mode) && c == DC4))
            prtchar(c);

        f_popped = 0;

        /* Handle the UTF8 conversion if we are in that mode */
        if ( tt_utf8 ) {
            USHORT * ucs2 = NULL;
            int rc = utf8_to_ucs2( (CHAR)(c & 0xFF), &ucs2 );
            if ( rc > 0 )
                return(0);
            else {
                if (rc < 0) {
                    c = 0xfffd;
                    f_pushed = 1;
                    c_pushed = *ucs2;
                } else
                    c = *ucs2;

                if (c == 0x2028 || c == 0x2029) { /* LS or PS */
                    c = CK_CR;
                    f_pushed = 1;
                    c_pushed = LF;
                }
                if ( ck_isunicode() ) {
                    if ( win95hsl && c >= 0x23BA && c <= 0x23BD )
                        c = tx_hslsub(c);
                    else if ( c >= 0xE000 && c <= 0xF8FF
#ifdef KUI
                              && !(drcsbuf[0] != NULL && IN_DRCS_1_RANGE(c) ||
                                   drcsbuf[1] != NULL && IN_DRCS_2_RANGE(c))
#endif /* KUI */
                            ){
                        /* DRCS soft character sets map into the unicode PUA range,
                         * so don't apply tx_usub to them. */
                        c = tx_usub(c);
                    }
                    if (win95lucida && c > 0x017f)
                        c = tx_lucidasub(c);
                } else {        
                    cx = c;
                    c = xl_tx[tcsl](cx);
                    if ( c < 0 )                /* Character could not be xlated */
                        c = '?' ;               /* to local character set */
                    if ( cx >= SP && c < SP ||
                         c >=128 && c <= 159)
                        literal_ch = TRUE ;
                }
            }
        }

        if ((ISVT220(tt_type_mode) ||
             ISANSI(tt_type_mode)) &&
             !xprint ) {                /* VT220 and above... */
                cx = tt_utf8 ? c : c & cmask & pmask;   /* C1 check must be masked */

            if (!tt_utf8 && ( GR->c1 ) &&
                 (cx > 127) && (cx < 160) /* It's a C1 character */
                 ) {
                f_pushed = 1;
                c_pushed = (c & 0x7F) | 0x40;
                c = ESC;
            }
        }
    }

    if (c >= 0) {                       /* Got character with no error? */
        if ( !xprint ) {
            if (!tt_utf8)
               c = c & cmask & pmask ;  /* Maybe strip 8th bit */
#ifndef NOXFER
            if ( (IsConnectMode() && autodl) ||
                 (!IsConnectMode() && inautodl) )
                autodown( c ) ;                 /* Download? */
#endif /* NOXFER */
            if (escstate == ES_NORMAL) {
                if ( !tt_utf8 )
                    c = rtolxlat(c);
            }
            else {
                c &= cmdmsk;            /* Apply command mask. */
            }

            if ((!debses) &&
                 ((tnlm &&              /* NEWLINE-MODE? */
                    (c == LF || c == FF || c == 11)) ||
                   (c == CK_CR && tt_crd ) /* CR-DISPLAY CRLF ? */
                   )) {
                cwrite((USHORT) CK_CR);    /* Yes, output CR */
                c = LF;                 /* and insert a linefeed */
            }
            cwrite((USHORT) c);
        } else {
            if (!GR->c1 && c >=128 && c <= 159) {
                literal_ch = TRUE;
                cwrite((USHORT) c);
                literal_ch = FALSE;
            } else
                cwrite((USHORT) c);
        }

#ifdef CK_TRIGGER
        if ( !xprint && tt_trigger[0] ) {
            int trigger = autoexitchk(c);
            if ( trigger > -1 ) {
                if (triggerval) /* Make a copy of the trigger */
                    free(triggerval);
                triggerval = NULL;
                triggerval = strdup(tt_trigger[trigger]);
                debug(F110,"scriptwrtbuf() triggerval",triggerval,0);
                ckmakmsg(termessage, sizeof(termessage),
                         "Trigger \"", triggerval,
                         "\" found.\n", NULL);
                SetConnectMode(FALSE,CSX_TRIGGER);
            }
        }
#endif /* CK_TRIGGER */
    }
    if (f_pushed)
        goto pushed ;

    /*debug(F100,"scriptwrtbuf returns","",0);*/
    return(0);
}

int
CSisNRC( int x )
{
    return cs_is_nrc(x);
}

/* Character-set final characters
 *
 *    A - British
 *    B - ASCII
 *    C - Finnish
 *    E - Norwegian/Dutch
 *    H - Swedish
 *    K - German
 *    Q - French Canadian
 *    R - French
 *    Y - Italian
 *    Z - Spanish
 *    0 - DEC Special Graphics
 *    4 - Dutch
 *    5 - Finnish
 *    6 - Norwegian/Dutch
 *    7 - Swedish
 *    < - DEC supplemental
 *    = - Swiss
 *
 */

int
isNRC( int x )
{
    switch ( x ) {
    case 'A':           /* FC_UKASCII TX_BRITISH */
    case 'B':           /* FC_USASCII TX_ASCII */
    case 'C': case '5': /* FC_FIASCII TX_FINNISH */
    case 'E': case '6': /* FC_NOASCII TX_NORWEGIAN */
    case 'H': case '7': /* FC_SWASCII TX_SWEDISH */
    case 'K':           /* FC_GEASCII TX_GERMAN */
    case 'Q':           /* FC_FCASCII TX_CN_FRENCH */
    case 'R': case 'f': /* FC_FRASCII TX_FRENCH */
    case 'Y':           /* FC_ITASCII TX_ITALIAN */
    case 'Z':           /* FC_SPASCII TX_SPANISH */
    case '4':           /* FC_DUASCII TX_DUTCH */
    case '=':           /* FC_CHASCII TX_SWISS */
    case '1':           /* DEC Alternate ROM - ASCII */
        return 1;
    default:
        return 0;
    }
}


/* See http://www.itscj.ipsj.or.jp/ISO-IR/ for Internation Char Set Registry */
unsigned char
charset( enum charsetsize size, unsigned short achar, struct _vtG * pG )
{
    unsigned char cs = TX_UNDEF ;
    unsigned char bchar = 0;
    unsigned char cchar = 0;
    unsigned char dchar = 0;
    BOOL bchar_is_intermediate = FALSE;
    int i;

    /* Read the character set name.
     * Soft-character sets allow 0-3 intermediate charaters followed by a final
     * while all of K95s built-in character sets have 0-1 intermediates followd
     * by a final.
     */
    if (achar >= ' ' && achar <= '/') {
        /* achar is an intermediate. */
        bchar = (escnext<=esclast)?escbuffer[escnext++]:0;
        if (bchar >= ' ' && bchar <= '/') {
            /* bchar is an intermediate */
            bchar_is_intermediate = TRUE;

            cchar = (escnext<=esclast)?escbuffer[escnext++]:0;
            if (cchar >= ' ' && cchar <= '/') {
                /* bchar is an intermediate */
                dchar = (escnext<=esclast)?escbuffer[escnext++]:0;
                /* dchar should be between '0' and '~' though I'm not sure there
                 * is much we can usefully do if that isn't the case */
            }
        }
    }

#ifdef KUI
    /* First, check DRCS buffers. The VT520 manual says if two fonts have the
     * same name the most recently loaded is used and specifically says that
     * the terminal searches for fonts in reverse order. My VT520 (v2.1) does
     * not do that - given the choice of two fonts with the same name, it always
     * picks the one in the first font buffer. */
    for (i = 0; i < DRCS_BUFFERS; i++) {
        if (drcsbuf[i] != NULL && drcsbuf[i]->is_96_chars == (size == cs96)) {
            if (drcsbuf[i]->name[0] == achar &&
                drcsbuf[i]->name[1] == bchar &&
                drcsbuf[i]->name[2] == cchar &&
                drcsbuf[i]->name[3] == dchar) {
                debug(F111, "Designate soft-font", drcsbuf[i]->name, i);
                switch (i) {
                    case 0: cs = TX_DRCS_1; break;
                    case 1: cs = TX_DRCS_2; break;
                    default: break;
                }
                if (cs != TX_UNDEF) break;
            }
        }
    }
#endif /* KUI */

    /* For all built-in character sets:
     * achar - intermediate or final
     * bchar - final or empty
     */

    if (cs == TX_UNDEF && !bchar_is_intermediate) {
        switch ( size ) {
            case cs94:
                switch ( achar ) {
#ifdef SN97801_5XX
                case '@':       /* International (new) */
                        break;
                case 'B':       /* International A (US-ASCII) */
                        break;
                case 'K':       /* German character set (GR-ASCII) */
                        break;
                case 'w':       /* Brackets character set (new) */
                        break;
                case 'c':       /* FACET character set (new) */
                        break;
                case 'v':       /* IBM character set (new) */
                        break;
                case 'u':       /* EURO symbols (new) */
                        break;
                case 't':       /* Mathematics symbols (new) */
                        break;
                case 'y':       /* Blanks (new) */
                        break;
                case 'x':       /* Load Area G2 (7-bit) or DRCS area (8-bit) if G0/G1 */
                        /* DRCS area always if G2/G3 */
                        break;
#endif /* SN97801_5XX */
                case '@':  /* 97801 - Not quite US ASCII but close */
                case 'A':
                        cs = TX_BRITISH ;
                        break;
                case 'B':       /* Use the default value for G[0] */
                        if (ISLINUX(tt_type_mode)) {
                            if ( pG == &G[0] )
                                cs = TX_ASCII;
                            else
                                cs = TX_8859_1 ;
                        } else if ( !(ISVT100(tt_type_mode) && decnrcm) ) {
                            /*
                            From VT330/340 install guide page 81.:
                            "When you select an NRC set in multinational mode,
                            the NRC set replaces the ASCII set."
                            */
#ifdef COMMENT
                            cs = G[0].def_designation;
#else /* COMMENT */
                            cs = dec_nrc;
#endif /* COMMENT */
                        }
                        else {
                            cs = TX_ASCII ;
                        }
                        break;
                case '1':       /* DEC Alternate ROM */
                        cs = TX_ASCII ;
                        break;
                case 'C':
                case '5':
                        cs = TX_FINNISH ;
                        break;
                case 'E':
                case '6':
                case '`':
                        cs = TX_NORWEGIAN ;
                        break;
                case 'G':
                case 'H':
                case '7':
                        cs = TX_SWEDISH ;
                        break;
                case 'K':
                        if ( ISLINUX(tt_type_mode) ) {       /* user defined */
                            if (pG == &G[0]) {
                                cs = TX_ASCII ;
                            } else {
                                cs = TX_CP850;               /* we will choose one */
                            }
                        } else
                            cs = TX_GERMAN ;
                        break;
                case 'Q':
                case '9':
                        cs = TX_CN_FRENCH ;
                        break;
                case 'R':
                case 'f':
                        cs = TX_FRENCH ;
                        break;
                case 'Y':
                        cs = TX_ITALIAN ;
                        break;
                case 'Z':
                        cs = TX_SPANISH ;
                        break;
                case '0':
                        cs = TX_DECSPEC ;
                        break;
                case '>':
                case '2':       /* DEC Alternate ROM - Special Graphics */
                        cs = TX_DECTECH ;
                        break;
                case '4':
                        cs = TX_DUTCH ;
                        break;
                case '<':
                        if ( ISVT320(tt_type_mode) ) {
                            /* DEC User Preferred Supplemental VT320 and higher */
                            cs = dec_upss ;
                        }
                        else {
                            cs = TX_DECMCS ;
                        }
                        break;
                case '=':
                        cs = TX_SWISS ;
                        break;
                case '%':
                        if (bchar == '5') {
                            cs = TX_DECMCS ;
                        }
                        else if (bchar == '6') {
                            cs = TX_PORTUGUESE ;
                        }
#ifdef COMMENT
                        else if (bchar == '0') {
                            cs = DEC TURKISH ;
                        }
                        else if (bchar == '=') {
                            cs = HEBREW NRCS ;
                        }
                        else if ( bchar == '2' )
                            cs = TURKISH NRCS;
                        else if ( bchar == '3' )
                            cs = SCS NRCS;
#endif /* COMMENT */
                        break;
                case 'L':
                        cs = TX_PORTUGUESE ;
                        break;
                case 'i':
                        cs = TX_HUNGARIAN ;
                        break;
                case 'J':
                        cs = TX_J201R ;
                        break;
                case 'I':
                        cs = TX_J201K ;
                        break;
                case '*':
                        cs = TX_IBMC0GRPH;  /* QANSI/Linux */
                        break;
                case 'U':               /* QANSI/Linux */
                case '?':               /* This is a MSK hack for Word Perfect */
                        if (pG == &G[0]) {
                            cs = TX_ASCII ;
                        } else {
                            cs = TX_CP437 ;
                        }
                        break;
                case 'c':       /* FACET character set (new) */
                        if ( IS97801(tt_type_mode) ) {
                            cs = TX_SNIFACET;
                        }
                        break;
                case 'e':       /* APL-ISO */
                        cs = TX_APL1;
                        break;
                case 'u':       /* EURO symbols (new) */
                        if ( IS97801(tt_type_mode) ) {
                            cs = TX_SNIEURO;
                        }
                        break;
                case 'v':       /* IBM character set (new) */
                        if ( IS97801(tt_type_mode) ) {
                            cs = TX_SNIIBM;
                        }
                        break;
                case 'w':       /* Brackets character set (new) */
                        if ( IS97801(tt_type_mode) ) {
                            cs = TX_SNIBRACK;
                        }
                        break;
#ifdef COMMENT
                case '"':
                        if ( bchar == '?' )
                            cs = DEC GREEK;
                        else if ( bchar == '4' )
                            cs = DEC HEBREW;
                        else if ( bchar == '>' )
                            cs = GREEK NRCS;
                        break;
                case '&':
                        if ( bchar == '4' )
                            cs = DEC CYRILLIC;
                        else if ( bchar == '5' )
                            cs = RUSSIAN NRC;
                        break;
#endif /* COMMENT */

                }
                break;

            case cs96:
                switch ( achar ) {
#ifdef SN97801_5XX
                case 'A':       /* 8859-1 */
                case 'B':       /* 8859-2 */
                case 'C':       /* 8859-3 */
                case 'D':       /* 8859-4 */
                case 'F':       /* 8859-5 (different) */
                case '@':       /* 8859-7 (different) */
                case 'T':       /* 8859-9 (different) */
                case 'x':       /* DRCS area */
#endif /* SN97801_5XX */
                case '<':       /* DEC User-preferred Supplemental */
                        cs = dec_upss ;
                        break;

                case 'A':
                        cs = TX_8859_1 ;
                        break;
                case 'B':
                        cs = TX_8859_2 ;
                        break;
                case 'C':
                        cs = TX_8859_3 ;
                        break;
                case 'D':
                        cs = TX_8859_4 ;
                        break;
                case 'F':
                        cs = IS97801(tt_type_mode) ? TX_8859_5 : TX_8859_7 ;
                        break;
                case '@':
                        cs = TX_8859_7 ;
                        break;
                case 'G':
                        cs = TX_8859_6 ;
                        break;
                case 'H':
                        cs = TX_8859_8 ;
                        break;
                case 'L':
                        cs = TX_8859_5 ;
                        break;
                case 'T': /* SNI-97801 */
                        if ( !IS97801(tt_type_mode) )
                            break;

                case 'M': /* DEC VT3xx */
                        cs = TX_8859_9 ;
                        break;

                case 'V':
                        cs = TX_8859_6 ;
                        break;

                case '%':
                        if (bchar == '5') {
                            cs = TX_DECMCS ;
                        }
                        break;
                case '*':
                        cs = TX_IBMC0GRPH;  /* QANSI/Linux */
                        break;
                case 'U':               /* QANSI/Linux */
                        /* fall through */
                case '?':               /* This is a MSK hack for Word Perfect */
                        if (pG == &G[0]) {
                            cs = TX_ASCII ;
                        } else {
                            cs = TX_CP437 ;
                        }
                        break;
                case 'b':
                        cs = TX_8859_15;    /* Latin 9 */
                        break;

                        /* Warning the following have been allocated officially */
                        /* the values below are not official.                   */
                case 'd':               /* Hack alert: DGI */
                        cs = TX_DGI ;
                        break;
                case 'e':               /* Hack alert: DG PC Graphics */
                        cs = TX_DGPCGRPH;
                        break;
                case 'f':               /* Hack alert: DG Line Drawing */
                        cs = TX_DGLDGRPH;
                        break;
                case 'g':               /* Hack alert: DG Word Processing Graphics */
                        cs = TX_DGWPGRPH;
                        break;
                case 'h':               /* Hack alert: HP Roman-8 */
                        cs = TX_HPR8;
                        break;
                case 'i':               /* Hack alert: HP Math-8 */
                        cs = TX_HPMATH;
                        break;
                case 'j':               /* Hack alert: HP Line-8 */
                        cs = TX_HPLINE;
                        break;
                }
        }
    }

    if ( cs <= MAXTXSETS ) {
        pG->designation = cs ;
        pG->size = size ;
        pG->c1 = cs_is_std(cs) ;
        pG->national = CSisNRC( cs ) ;
        pG->rtoi = xl_u[cs] ;
        pG->itol = xl_tx[tcsl] ;
        pG->ltoi = xl_u[tcsl] ;
        pG->itor = xl_tx[cs] ;
    }
    else if ( cs != TX_UNDEF ) {
        debug(F110,"charset - ERROR","cs != TX_UNDEF",0);
        pG->designation = cs ;
        pG->c1 = FALSE ;
        pG->national = FALSE;
        pG->rtoi = NULL ;
        pG->itol = NULL ;
        pG->itor = NULL ;
        pG->ltoi = NULL ;
    }
    return cs ;
}

/* This function tries to turn a TX_ character set identifier back into the
 * character(s) used to designate it. Its implemented for the benefit of the
 * VT320 Cursor Information Report, so charactersets specific to non-VT
 * emulations aren't fully represented here and may just produce a "?".
 * Result will always be one or two characters.
 *
 * TODO: DECUPSS
 */
char*
csetchar(enum charsetsize size, int cset) {
    char result[2] = {'\0', '\0'};
    switch (size) {
    case cs94: {
        switch (cset) {
        case TX_BRITISH:
            return "A";     /* Or @ */
        case TX_ASCII:
            return "B";
        case TX_FINNISH:
            return "5";
        case TX_NORWEGIAN:
            return "`";
        case TX_SWEDISH:
            return "7";
        case TX_GERMAN:
            return "K";
        case TX_CN_FRENCH:
            return "9";
        case TX_FRENCH:
            return "R";
        case TX_ITALIAN:
            return "Y";
        case TX_SPANISH:
            return "Z";
        case TX_DECSPEC:
            return "0";
        case TX_DECTECH:
            return ">";
        case TX_DUTCH:
            return "4";
        case TX_DECMCS:
            if (!ISVT320(tt_type_mode)) {
                return "<";
            }
            return "%5";
        case TX_SWISS:
            return "=";
        case TX_PORTUGUESE:
            return "%6";  /* or L */
        case TX_HUNGARIAN:
            return "i";
        case TX_J201R:
            return "J";
        case TX_J201K:
            return "I";
        case TX_IBMC0GRPH:
            return "*";
        case TX_APL1:
            return "e";
        default:
            break;
        }

        break;
    }
    case cs96: {
        switch (cset) {
        case TX_8859_1:
            return "A";
        case TX_8859_2:
            return "B";
        case TX_8859_3:
            return "C";
        case TX_8859_4:
            return "D";
        case TX_8859_7:
            return "@";
        case TX_8859_6:
            return "G";
        case TX_8859_8:
            return "H";
        case TX_8859_5:
            return "L";
        case TX_8859_9:
            return "M";
        case TX_DECMCS:
            return "%5";
        case TX_IBMC0GRPH:
            return "*";
        case TX_8859_15:
            return "b";
        default:
            break;
        }

        break;
        }
    }
    return "?";
}

void
resetcolors( int x )
{
    if ( !x )
        attribute = defaultattribute ;
    else {
        if ( decscnm ) {
            defaultattribute =
                byteswapcolors(colornormal);
            underlineattribute =
                byteswapcolors(colorunderline);
            italicattribute = 
                byteswapcolors(coloritalic);
            reverseattribute =
                byteswapcolors(colorreverse);
            graphicattribute =
                byteswapcolors(colorgraphic);
            blinkattribute =
                byteswapcolors(colorblink);
            boldattribute =
                byteswapcolors(colorbold);
			dimattribute =
				byteswapcolors(colordim);
            crossedoutattribute =
                byteswapcolors(colorcrossedout);
        }
        else {
            defaultattribute = colornormal ;
            underlineattribute = colorunderline;
            italicattribute = coloritalic;
            reverseattribute = colorreverse;
            graphicattribute = colorgraphic;
            blinkattribute = colorblink;
            boldattribute  = colorbold;
			dimattribute   = colordim;
            crossedoutattribute = colorcrossedout;
        }
        attribute = defaultattribute ;
        borderattribute = colorborder ;
		use_bold_attr = bold_is_color;
		use_blink_attr = blink_is_color;
    }
}

void
os2debugoff() {                         /* Turn off debugging from outside */
    debug(F100,"os2debugoff","",0);
    attribute = defaultattribute;
}

void
os2bold() {                             /* Toggle boldness from the outside */
    tn_bold = 1 - tn_bold;
}

void                            /* Toggle session debugging */
flipdebug() {
    if (debses) {
        attribute = defaultattribute;   /* Back to normal coloring */
        setdebses(0);                     /* Turn off session debug flag */
    } else {
        setdebses(1);                     /* Turn on session debug flag */
    }
    if (!scrollflag[VTERM] && status_saved < 0)
      ipadl25();
}


#ifdef NETCONN
#ifdef TCPSOCKET
int do_tn_cmd(CHAR x) {
    CHAR temp[3];

    if (network && IS_TELNET()) { /* TELNET */
        temp[0] = (CHAR) IAC;
        temp[1] = x;
        temp[2] = NUL;
        ttol((CHAR *)temp,2);

        if (tn_deb || debses || deblog) {
            extern char tn_msg[];
            ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(x),NULL,NULL);
            debug(F101,tn_msg,"",x);
            if (tn_deb || debses) tn_debug(tn_msg);
        }
    } else
      bleep(BP_FAIL);
    return(0);
}
#endif /* TCPSOCKET */
#endif /* NETCONN */

#ifndef NOKVERBS
void
bookmarkset( int vmode )
{
    int mark = 0 ;
    CHAR x1;
    con_event evt ;
#ifdef KUI
    int term_status_backup = tt_status[vmode];
#endif /* KUI */

    save_status_line();
    decssdt_override=TRUE; /* Force rendering of SSDT_INDICATOR temporarily */
#ifdef KUI
    settermstatus(TRUE);   /* Force the status line on if it isn't already */
#endif /* KUI */
    escapestatus[vmode] = TRUE ;
    strcpy(exittext,"Cancel: Space"); /* Make special one */
    strcpy(usertext," SET MARK: [ ]"); /* with mini-echo-buffer */
    if (vik.help > 255 && keyname(vik.help))
        sprintf(helptext, "Help: %s", keyname(vik.help));       /* safe */
    VscrnIsDirty(vmode);  /* status line needs to be updated */

    do {
        evt = congev(vmode,-1) ;
        switch (evt.type) {
        case key:
#ifdef COMMENT
            x1 = mapkey(evt.key.scancode); /* Get value from keymap */
#else
            x1 = evt.key.scancode ;
#endif
            break;
        case kverb:
            x1 = evt.kverb.id & ~F_KVERB;
            break;
        case macro:
            if ( evt.macro.string )
                free( evt.macro.string ) ;
            x1 = 0;
            break;
        case literal:
            if ( evt.literal.string )
                free( evt.literal.string ) ;
            x1 = 0;
            break;
        case csi:
        case esc:
        default:
            x1 = 0 ;
        }
        if ( x1 == K_HELP )
            popuphelp(vmode,hlp_bookmark);
    } while ( x1 == K_HELP );
    if ((x1 < '0') || (x1 > '9')) {
        if (x1 != SP)
            bleep(BP_FAIL);
        goto bookmark_exit;
    }

    sprintf(usertext," SET MARK: [%c]", x1); /* Echo char */
    VscrnIsDirty(vmode);  /* status line needs to be updated */
    msleep(500);      /* let the user see it for a bit */
    mark = x1 - '0' ;
    VscrnSetBookmark( vmode, mark,
                      (tt_roll[vmode] && scrollflag[vmode]) ?
                      VscrnGetScrollTop(vmode, FALSE) : VscrnGetTop(vmode, FALSE, TRUE) ) ;

  bookmark_exit:                        /* Common exit point */
    escapestatus[vmode] = FALSE ;
#ifdef KUI
    settermstatus(term_status_backup);  /* Restore previous setting */
#endif /* KUI */
    decssdt_override=FALSE;           /* Done with temporarily SSDT_INDICATOR */
    restore_status_line();              /* Restore status line */
    return;
}

int
bookmarkget( int vmode )
{
   return VscrnGetBookmark( vmode, 0 ) ;
}

void
bookmarkreset( int vmode )
{
   VscrnSetBookmark( vmode, 0, -1 ) ;
}

void
bookmarkjump( int vmode )
{
    int mark = 0, bookmark ;
    CHAR x1;
    con_event evt ;

    save_status_line();
    decssdt_override=TRUE; /* Force rendering of SSDT_INDICATOR temporarily */
    escapestatus[vmode] = TRUE ;
    strcpy(exittext,"Cancel: Space"); /* Make special one */
    strcpy(usertext," GO MARK: [ ]"); /* with mini-echo-buffer */
    if (vik.help > 255 && keyname(vik.help))
        sprintf(helptext, "Help: %s", keyname(vik.help));
    VscrnIsDirty(vmode);  /* status line needs to be updated */

    do {
        evt = congev(vmode,-1) ;
        switch (evt.type) {
        case key:
#ifdef COMMENT
            x1 = mapkey(evt.key.scancode); /* Get value from keymap */
#else
            x1 = evt.key.scancode ;
#endif
            break;
        case kverb:
            x1 = evt.kverb.id & ~F_KVERB;
            break;
        case macro:
            if ( evt.macro.string )
                free( evt.macro.string ) ;
            x1 = 0;
            break;
        case literal:
            if ( evt.literal.string )
                free( evt.literal.string ) ;
            x1 = 0;
            break;
        case csi:
        case esc:
        default:
            x1 = 0 ;
        }
        if ( x1 == K_HELP )
            popuphelp(vmode,hlp_bookmark);
    } while ( x1 == K_HELP );
    if ((x1 < '0') || (x1 > '9')) {
        if (x1 != SP)
            bleep(BP_FAIL);
        goto bookmark_exit;
    }

    sprintf(usertext," GO MARK: [%c]", x1); /* Echo char */
    VscrnIsDirty(vmode);  /* status line needs to be updated */
    msleep(500);      /* let the user see it for a bit */
    mark = x1 - '0' ;
    bookmark = VscrnGetBookmark( vmode, mark ) ;

    if ( bookmark < 0 )
    {
        bleep(BP_FAIL);
        goto bookmark_exit;
    }

    if (!tt_roll[vmode]) {
        if ( VscrnSetTop(vmode, bookmark, FALSE, TRUE) < 0 )
            bleep(BP_WARN) ;
    }
    else {
        if ( VscrnSetScrollTop(vmode, bookmark) < 0 )
            bleep(BP_WARN);
    }

  bookmark_exit:                        /* Common exit point */
    decssdt_override=FALSE;           /* Done with temporarily SSDT_INDICATOR */
    restore_status_line();              /* Restore status line */
    escapestatus[vmode] = FALSE ;
    return;
}

/*---------------------------------------------------------------------------*/
/* gotojump                                                 | Page: View     */
/*---------------------------------------------------------------------------*/
void
gotojump( int vmode )
{
   int line = 0, negative = 0, maxval = 0 ;
   CHAR x1;
   con_event evt ;

   save_status_line();
   escapestatus[vmode] = TRUE ;

   do {
      maxval = (VscrnGetEnd(vmode, FALSE, TRUE) - VscrnGetBegin(vmode, FALSE, TRUE) - VscrnGetHeightEx(vmode, FALSE)
                 + VscrnGetBufferSize(vmode, FALSE, TRUE))%VscrnGetBufferSize(vmode, FALSE, TRUE) ;

      if ( negative && line < -maxval )
      {
         line = -maxval ;
         bleep(BP_NOTE);
      }

      if ( !negative && line > (maxval+1) )
      {
         line = maxval+1 ;
         bleep(BP_NOTE);
      }

       strcpy(exittext,"Cancel: Space"); /* Make special one */
       sprintf(usertext," GOTO: [%10d]",line); /* with mini-echo-buffer */
       helptext[0] = '\0' ;
       if (vik.help > 255 && keyname(vik.help))
           sprintf(hostname, "Help: %s", keyname(vik.help));
       VscrnIsDirty(vmode);  /* status line needs to be updated */

       evt = congev(vmode,-1) ;
       switch (evt.type) {
       case key:
#ifdef COMMENT
           x1 = mapkey(evt.key.scancode); /* Get value from keymap */
#else
           x1 = evt.key.scancode ;
#endif
           break;
       case kverb:
           x1 = evt.kverb.id & ~F_KVERB;
           break;
       case macro:
           if ( evt.macro.string )
               free( evt.macro.string ) ;
           x1 = 0;
           break;
       case literal:
           if ( evt.literal.string )
               free( evt.literal.string ) ;
           x1 = 0;
           break;
       case csi:
       case esc:
       default:
           x1 = 0 ;
       }

       if ( x1 == K_HELP )
       {
           popuphelp(vmode,hlp_bookmark);
       }
       else if ( x1 == '-' )
       {
           negative = (negative ? FALSE : TRUE) ;
       }
       else if ( x1 >= '0' && x1 <= '9' )
       {
           line = line * 10 + (x1-'0') ;
       }
       else if ( x1 == 8 || x1 == 127 )
       {
           line = line / 10 ;
       }
       else if ( x1 == 13 )
       {
           break;
       }
       else
       {
           if ( x1 != ' ' )
               bleep(BP_FAIL);
           goto bookmark_exit;
       }

       if ( ( negative && line > 0 ) || ( !negative && line < 0 ) )
           line = -line ;

   } while ( TRUE );

    msleep(500);      /* let the user see it for a bit */

    if ( line <= 0 )
    {
        if (!tt_roll[vmode]) {
            if ( VscrnSetTop(vmode, VscrnGetEnd(vmode, FALSE, TRUE)-VscrnGetHeightEx(vmode,FALSE)+line, FALSE, TRUE) < 0 )
                bleep(BP_WARN) ;
        }
        else {
            if ( VscrnSetScrollTop(vmode, VscrnGetEnd(vmode, FALSE, TRUE)-VscrnGetHeightEx(vmode, FALSE)+line) < 0 )
                bleep(BP_WARN);
        }
    }
    else
    {
        if (!tt_roll[vmode]) {
            if ( VscrnSetTop(vmode, VscrnGetBegin(vmode,FALSE,TRUE)+line-1, FALSE, TRUE) < 0 )
                bleep(BP_WARN) ;
        }
        else {
            if ( VscrnSetScrollTop(vmode, VscrnGetBegin(vmode,FALSE,TRUE)+line-1) < 0 )
                bleep(BP_WARN);
        }
    }

  bookmark_exit:                        /* Common exit point */
    restore_status_line();              /* Restore status line */
    escapestatus[vmode] = FALSE ;
    return;
}

#define SEARCHSTRING_LEN    63

/*---------------------------------------------------------------------------*/
/* search                                                   | Page: View     */
/*---------------------------------------------------------------------------*/
BOOL
search( BYTE vmode, BOOL forward, BOOL prompt )
{
#ifdef DCMDBUF
   extern int * inpcas;
#else
   extern int inpcas[] ;
#endif /* DCMDBUF */
   static char searchstring[SEARCHSTRING_LEN] = "" ;
   CHAR x1;
   con_event evt ;
   int line = 1 ;
   int found = 0 ;
   static int len = 0 ;
   static int row=-1, col=-1 ;
#ifdef KUI
    int term_status_backup = tt_status[vmode];
#endif /* KUI */
	vscrn_page_t *page = &vscrn_view_page(vmode);

    if ( prompt )
    {
        decssdt_override=TRUE; /* Force rendering of SSDT_INDICATOR temporarily */
#ifdef KUI
        settermstatus(TRUE);   /* Force the status line on if it isn't already */
#endif /* KUI */
        save_status_line();
        escapestatus[vmode] = TRUE ;

        do {
            len = strlen( searchstring ) ;
            strcpy(exittext,"Cancel: ESC"); /* Special one with edit buffer */
            sprintf(usertext," %s: [%-16s]",forward ? "SEARCH>" : "<SEARCH",
                  len <= 16 ? searchstring : &searchstring[len-16] );
            helptext[0] = '\0' ;
            if (vik.help > 255 && keyname(vik.help))
                sprintf(hostname, "Help: %s", keyname(vik.help));
            VscrnIsDirty(vmode);  /* status line needs to be updated */

            evt = congev(vmode,-1) ;
            switch (evt.type) {
            case key:
#ifdef COMMENT
                x1 = mapkey(evt.key.scancode); /* Get value from keymap */
#else
                x1 = evt.key.scancode ;
#endif
                break;
            case kverb:
                x1 = evt.kverb.id & ~F_KVERB;
                break;
            case macro:
                if ( evt.macro.string )
                    free( evt.macro.string ) ;
                x1 = 0;
                break;
            case literal:
                if ( evt.literal.string )
                    free( evt.literal.string ) ;
                x1 = 0;
                break;
            case esc:
            case csi:
            default:
                x1 = 0 ;
            }

            if ( x1 == K_HELP )
            {
                popuphelp(vmode,hlp_search);
            }
            else if ( x1 >= ' ' && x1 <= 126 || x1 >= 128 /*always true: && x1 <= 255*/ )
            {
                if ( len >= SEARCHSTRING_LEN - 1 ) {
                    bleep(BP_WARN);
                }
                else {
                    searchstring[len] = x1 ;
                    searchstring[len+1] = '\0' ;
                }
            }
            else if ( x1 == 8 || x1 == 127 )
            {
                if (len - 1 < 0) {
                    bleep(BP_WARN);
                } else {
                    searchstring[len-1] = '\0' ;
                }
            }
            else if ( x1 == 13 )
            {
                break;
            }
            else if ( x1 == 21 )
            {
                searchstring[0] = '\0' ;
                len = 0 ;
            }
            else
            {
                if ( x1 != ESC )
                    bleep(BP_FAIL);
                goto search_exit;
            }
        } while ( TRUE );

        msleep(500);      /* let the user see it for a bit */
#ifdef KUI
        settermstatus(term_status_backup);  /* Restore previous setting */
#endif /* KUI */
        decssdt_override=FALSE;         /* Done with temporarily SSDT_INDICATOR */
        restore_status_line();          /* Restore status line */
        escapestatus[vmode] = FALSE ;

        col = VscrnGetCurPosEx(vmode,FALSE)->x ;
        row = (( markmodeflag[vmode] ? VscrnGetTop(vmode, FALSE, TRUE) : VscrnGetScrollTop(vmode, FALSE) )
                + VscrnGetCurPosEx(vmode,FALSE)->y) % VscrnGetBufferSize(vmode, FALSE, TRUE) ;
    }
    else
    {
        if ( row < 0 || col < 0 || !searchstring || !searchstring[0] )
        {
            bleep(BP_FAIL);
            goto search_exit ;
        }

        /* advance the cursor */
        if ( forward )
        {
            col++ ;
            if ( col == page->lines[row%page->linecount].width )
            {
                if ( row != VscrnGetEnd(vmode,FALSE,TRUE) )
                {
                    col = 0 ;
                    row++ ;
                }
                else
                {
                    col--;
                    goto search_exit;
                }
            }
            if ( row >= VscrnGetBufferSize( vmode, FALSE, TRUE ) )
                row = 0 ;
        }
        else
        {
            col-- ;
            if ( col < 0 )
            {
                if ( row != VscrnGetBegin(vmode, FALSE, TRUE) )
                {
                    row-- ;
                    col = page->lines[row%page->linecount].width - 1 ;
                }
                else
                {
                    col++;
                    goto search_exit;
                }
            }
            if ( row < 0 )
                row = VscrnGetBufferSize(vmode, FALSE, TRUE) -1 ;
        }
    }

    /* Now we have the string to search for */
    /* so lets search for it ???            */
    {
        char *s = searchstring ;
        int y=len,i;
        char *xp, *xq = (char *)0;
        CHAR c;

        i = 0 ;                         /* String pattern match position */

        if (!inpcas[cmdlvl] || !forward)
        {               /* INPUT CASE = IGNORE?  */
            xp = malloc(y+2);           /* Make a separate copy of the */
            if (!xp)
            {                   /* search string. */
                row = col = -1 ;
                return(found);
            }
            else
                xq = xp;                        /* Keep pointer to beginning. */

            if ( !forward )
            {
                xp = xp + len ;
                *xp = NUL ;
                xp--;
            }

            while (*s) {                        /* Yes, convert to lowercase */
                *xp = *s;
                if (!inpcas[cmdlvl] && isupper(*xp))
                    *xp = tolower(*xp);
                if ( forward )
                    xp++;
                else
                    xp--;
                s++;
            }
            if ( forward )
                *xp = NUL;                      /* Terminate it! */
            s = xq;                             /* Move search pointer to it. */
        }

        while (TRUE)
        {
            c = page->lines[row].cells[col].c;                   /* Get next character */
            if (!inpcas[cmdlvl])
            {           /* Ignore alphabetic case? */
                if (isupper(c))
                    c = tolower(c); /* Yes */
            }
            debug(F000,"search char","",c);
            debug(F000,"compare char","",(CHAR) s[i]);
            if (c == s[i])
            {           /* Check for match */
                if ( i==0 )
                    VscrnUnmarkAll( vmode ) ;
                VscrnMark( vmode, row, col, col );
                i++;                    /* Got one, go to next character */
            }
            else
            {                   /* Don't have a match */
                int j;
                for (j = i; i > 0; )
                {       /* [jrs] search backwards for it  */
                    i--;
                    if (c == s[i])
                    {
                        if (!strncmp(s,&s[j-i],i))
                        {
                            /* This code assumes the matching sub pattern */
                            /* appears entirely on one line.  But there   */
                            /* are situations where it might be split.    */
                            /* What then? */
                            VscrnUnmarkAll(vmode);
                            if ( forward )
                                VscrnMark( vmode, row, col-i, col ) ;
                            else
                                VscrnMark( vmode, row, col, col+i ) ;
                            i++;
                            break;
                        }
                    }
                }
            }                           /* [jrs] or return to zero from -1 */
            if (s[i] == '\0')
            {           /* Matched all the way to end? */
                VscrnMark( vmode, row, col, col ) ;
                found = 1;                      /* Yes, */
                line = row ;
                break;                  /* done. */
            }

            /* check to see if we hit the begin or end of vscrn */
            if ( forward && row == VscrnGetEnd(vmode,FALSE,TRUE) && col == page->lines[row%page->linecount].width-1 ||
                 !forward && row == VscrnGetBegin(vmode,FALSE,TRUE) && col == 0 )
                break;    /* search string not found */

            /* advance the cursor */
            if ( forward )
            {
                col++ ;
                if ( col == page->lines[row%page->linecount].width )
                {
                    if ( row != VscrnGetEnd(vmode,FALSE,TRUE) )
                    {
                        col = 0 ;
                        row++ ;
                    }
                    else
                    {
                        col--;
                        break;
                    }
                }
                if ( row >= VscrnGetBufferSize( vmode, FALSE, TRUE ) )
                    row = 0 ;
            }
            else
            {
                col-- ;
                if ( col < 0 )
                {
                    if ( row != VscrnGetBegin(vmode, FALSE, TRUE) )
                    {
                        row-- ;
                        col = page->lines[row%page->linecount].width - 1 ;
                    }
                    else
                    {
                        col++;
                        break;
                    }
                }
                if ( row < 0 )
                    row = VscrnGetBufferSize(vmode, FALSE, TRUE) -1 ;
            }
        }

        if ((!inpcas[cmdlvl] || !forward) && xq)
            free(xq); /* Free this if it was malloc'd. */
    }

    /* okay, did we find it?  if so, go there */
    if ( found )
    {
        if ( row >= VscrnGetTop(vmode,FALSE,TRUE) && row <= VscrnGetEnd(vmode,FALSE,TRUE) ||
             row <= VscrnGetEnd(vmode,FALSE,TRUE)
             && (row + VscrnGetBufferSize(vmode, FALSE, TRUE)) > VscrnGetTop(vmode,FALSE,TRUE)
             && VscrnGetEnd(vmode,FALSE,TRUE) < VscrnGetTop(vmode,FALSE,TRUE)
             )
        {
            if ( tt_roll[vmode] )
                VscrnSetScrollTop(vmode, VscrnGetTop(vmode,FALSE,TRUE) ) ;
            VscrnSetCurPosEx( vmode, col,
                            (row - VscrnGetTop(vmode,FALSE,TRUE) +
                              VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))
                            %(VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0)),
                            FALSE ) ;
        }
        else
        {
            if(tt_roll[vmode])
                VscrnSetScrollTop( vmode, row ) ;
            else
                VscrnSetTop( vmode, row, FALSE, TRUE ) ;
            VscrnSetCurPosEx( vmode, col, 0, FALSE ) ;
        }
    }

  search_exit:                  /* Common exit point */
    if ( !found )
    {
        VscrnUnmarkAll(vmode);
        row = col = -1 ;             /* start next search from current cursor position */
    }

    return(found);
}

void
dokcompose( int mode, int ucs2 )
{
    int i;
    USHORT x[4]={SP,SP,SP,SP}, c=0;
    con_event evt;
#ifdef KUI
    int term_status_backup = tt_status[vmode];
#endif /* KUI */

    if (txrinfo[GL->designation]->family != AL_ROMAN ||
         txrinfo[GR->designation]->family != AL_ROMAN ) {
        bleep(BP_WARN);         /* Not Latin character-set */
        goto compose_exit;
    }
    save_status_line();
    decssdt_override=TRUE; /* Force rendering of SSDT_INDICATOR temporarily */
#ifdef KUI
    settermstatus(TRUE);   /* Force the status line on if it isn't already */
#endif /* KUI */
    escapestatus[mode] = TRUE ;
    strcpy(exittext,"Cancel: Space"); /* Make special one */
    if (vik.help > 255 && keyname(vik.help))
        sprintf(helptext, "Help: %s", keyname(vik.help));

    for (i=0; i < (ucs2 ? 4 : 2); i++)  {
        /* mini-echo-buffer */
        if ( ucs2 )
            sprintf(usertext," UNICODE: [%c%c%c%c]",x[0],x[1],x[2],x[3]);
        else
            sprintf(usertext," COMPOSE: [%c%c]",x[0],x[1]);
        VscrnIsDirty(mode);        /* Status line needs update */

        do {
            evt = congev(mode,-1) ;
            switch (evt.type) {
            case key:
                x[i] = evt.key.scancode ;
                break;
            case kverb:
                x[i] = evt.kverb.id & ~F_KVERB;
                break;
            case macro:
                if ( evt.macro.string )
                    free( evt.macro.string ) ;
                x[i] = SP;
            break;
            case literal:
                if ( evt.literal.string )
                    free( evt.literal.string ) ;
                x[i] = SP;
            break;
            case csi:
            case esc:
            default:
                x[i] = SP;
            }
            if ( x[i] == K_HELP )
                popuphelp(mode,ucs2 ? hlp_ucs2 : hlp_compose);
        } while ( x[i] == K_HELP );
        if ((x[i] <= SP) || (x[i] > 0x7E) || ucs2 && !isxdigit(x[i]) ) {
            if (x[i] != SP)
                bleep(BP_WARN);
            goto compose_exit;
        }
    }

    if ( ucs2 ) {
        char hexstr[5];

        sprintf(usertext," UNICODE: [%c%c%c%c]",x[0],x[1],x[2],x[3]);
        VscrnIsDirty(mode);        /* Status line needs update */

        for ( i=0;i<4;i++ )
            hexstr[i] = x[i];
        hexstr[4] = NUL;

        c = hextoulong(hexstr,4);
    } else {
        sprintf(usertext," COMPOSE: [%c%c]",x[0],x[1]);
        VscrnIsDirty(mode);        /* Status line needs update */

        if (tcsl == TX_CP852) {     /* East European */
            for (i = 0; i < nl2ktab; i++) /* Look up the 2-char sequence */
                if ((x[0] == l2ktab[i].c1) && (x[1] == l2ktab[i].c2))
                    break;
            if (i >= nl2ktab) {     /* Not found */
                bleep(BP_WARN);
                goto compose_exit;
            } else c = l2ktab[i].c3; /* Latin-2 Character we found */

            /* Convert to Unicode */
            c = (*xl_u[TX_8859_2])(c);
        } else {
            for (i = 0; i < nl1ktab; i++) /* Look up the 2-char sequence */
                if ((x[0] == l1ktab[i].c1) && (x[1] == l1ktab[i].c2))
                    break;
            if (i >= nl1ktab) {         /* Not found */
                bleep(BP_WARN);
                goto compose_exit;
            } else
                c = l1ktab[i].c3;    /* Latin-1 Character we found */

            /* Convert to Unicode */
            c = (*xl_u[TX_8859_1])(c);

            /* Convert c to local character set */
            c = (*xl_tx[tcsl])(c);
        }
    }

    /* We know have a UCS2 value in 'c'.  Output it */
    if ( mode == VTERM ) {
        /* Convert c to remote character set */
        if ( tt_utf8 ) {
            CHAR * bytes = NULL;
            int count,i;

            count = ucs2_to_utf8( c, &bytes );
            for ( i=0; i<count ; i++ )
                sendcharduplex(bytes[i],TRUE);   /* Send it */
        } else {
            c = (*xl_tx[tcsr])(c);
            sendcharduplex(c,TRUE);             /* Send it */
        }
    } else {
        /* Convert c to local character set */
        c = (*xl_tx[tcsl])(c);
        putkey(mode,c);
    }
    msleep(333);                /* Some time to look at minibuffer */

  compose_exit:                 /* Common exit point */
#ifdef KUI
    settermstatus(term_status_backup);  /* Restore previous setting */
#endif /* KUI */
    decssdt_override=FALSE;           /* Done with temporarily SSDT_INDICATOR */
    restore_status_line();      /* Restore status line */
    escapestatus[mode] = FALSE ;
}

/* Set the Keyboard Mode (English, Russian, Hebrew, ...) */

void
set_kb_mode( int kb_mode ) {
#ifdef COMMENT
    static int tcsl_sav = -1;
    int i,x;
#endif /* COMMENT */

    if ( tt_kb_mode == kb_mode )
        return;

    tt_kb_mode = kb_mode;

#ifdef COMMENT
    /* I added this code because I didn't think that Russian and Hebrew  */
    /* keyboard modes could work without it.  However, it turns out that */
    /* sendcharduplex() has a special check to convert from CP866 to the */
    /* remote character set if Russian keyboard mode is in use or from   */
    /* CP862 if Hebrew is in use.  Therefore, this code is not necessary */

    switch ( kb_mode ) {
    case KBM_RU:
        if ( tcsl_sav == -1 )
            tcsl_sav = tcsl;
        tcsl = TX_CP866;
        break;
    case KBM_HE:
        if ( tcsl_sav == -1 )
            tcsl_sav = tcsl;
        tcsl = TX_CP862;
        break;
    default:
        if ( tcsl_sav != -1 ) {
            tcsl = tcsl_sav;
            tcsl_sav = -1;
        }
    }

    for (i = 0; i < 4; i++) {
        x = G[i].designation;
        G[i].c1 = (x != tcsl) && cs_is_std(x);
        x = G[i].def_designation;
        G[i].def_c1 = (x != tcsl) && cs_is_std(x);

        /* initialize DEC Graphic Set Translation functions if necessary */
        G[i].rtoi = xl_u[G[i].designation];
        G[i].itol = xl_tx[tcsl] ;
        G[i].ltoi = xl_u[tcsl] ;
        G[i].itor = xl_tx[G[i].designation];
        G[i].init = FALSE ;
    }
#endif /* COMMENT */
}


/*  D O K V E R B  --  Execute a keyboard verb  */

void
dokverb(int mode, int k) {                        /* 'k' is the kverbs[] table index. */
    extern int activecmd ;
    int x;
    char escbuf[10];                    /* For building key escape sequences */
/*
  Items are grouped according to function, and checked approximately
  in order of how frequently they are used.
*/
    k &= ~(F_KVERB);                    /* Clear KVERB flag */

    if (k >= K_ACT_MIN && k <= K_ACT_MAX) {

        switch (k) {                    /* Common Kermit actions first ... */
        case K_EXIT:  /* \Kexit: */
            if ( mode == VTERM ) {
                if ( markmodeflag[mode] != notmarking ) {
                    markmode(mode,k);
                }
                else if ( tt_escape )
                    SetConnectMode(FALSE,CSX_ESCAPE);/*   Exit from terminal emulator */
            }
            else if ((mode == VCMD) && !(what & W_XFER)) {
                if (
#ifndef NOSPL
                 cmdlvl == 0
#else
                 tlevel == -1
#endif /* NOSPL */
                   ) {
                    x = conect(1);
#ifdef KUI
                    KuiSetTerminalConnectButton(x);
#endif /* KUI */
                } else
                    bleep(BP_WARN);
            }
            return;

        case K_QUIT:  /* \Kquit: */
            if ( markmodeflag[mode] != notmarking ) {
                markmode(mode,k);
                /* return ; */
            }
            if ( mode == VTERM ) {
                quitnow = 1;
                strcpy(termessage, "Hangup and quit.\n");
                SetConnectMode(0,CSX_USERDISC);
            }
            else {
                ttclos(0);
                doexit(GOOD_EXIT,0);
            }
            return;

        case K_BREAK:                 /* \Kbreak */
            if (mode == VTERM && !kbdlocked()) {
                int iosav = term_io;
                term_io = FALSE;
                msleep(750);               /* Allow term thread to notice */
                ttsndb();
                term_io = iosav;
            }
            return;
        case K_DOS:                   /* \Kdos or \Kos2 */
            os2push(); 
            return;                   /*   Push to system */
        case K_RESET:                 /* \Kreset */
            if ( mode == VTERM )
              doreset(1); 
            return;         /*   Reset terminal emulator */
        case K_HELP: {        /* \Khelp */
              enum helpscreen x = hlp_normal ;
              if ( markmodeflag[mode] != notmarking ) {
                  markmode(mode,k);
                  return ;
              }
              if ( scrollstatus[mode] ) {
                  scrollback(mode,k);
                  return ;
              }
              while ( popuphelp(mode,x) == ( F_KVERB | K_HELP ) )
#ifdef OS2MOUSE
                  switch ( x ) {
                  case hlp_normal:
                      x = hlp_rollback;
                      break;
                  case hlp_rollback:
                      x = hlp_mouse;
                      break;
                  case hlp_mouse:
                      x = hlp_normal;
                      break;
                  }
#else /* OS2MOUSE */
            switch ( x ) {
            case hlp_normal:
                x = hlp_rollback;
                break;
            case hlp_rollback:
                x = hlp_normal;
                break;
            }
#endif /* OS2MOUSE */
              return;   /*   Pop-up help message */
          }
          case K_PRTCTRL:               /* \Kprtscn,\Kprtctrl */
            if ( mode == VTERM )
              if ( xprint ) {               /*   Toggle Printer Ctrl mode on/off */
                  xprint = FALSE;         /*   It's on, turn it off */
                  if ( !cprint && !aprint )
                    printeroff();
                  else
                    ipadl25();
              } else {                    /*   vice versa ... */
                  xprint = TRUE ;
                  printeron();
              }
            return;
        case K_PRTAUTO:               /* \Kprtauto */
            if ( mode == VTERM )
              if ( aprint ) {         /*   Toggle printer auto mode on/off */
                  setaprint(FALSE);   /*   It's on, turn it off */
                  if ( !cprint && !xprint )
                    printeroff();
                  else
                    ipadl25();
              } else {                    /*   vice versa ... */
                  setaprint(TRUE);
                  printeron();
              }
            return;
        case K_PRTCOPY:               /* \Kprtcopy */
            if ( mode == VTERM )
              if ( cprint ) {     /*   Toggle printer copy mode on/off */
                  cprint = FALSE;         /*   It's on, turn it off */
                  if ( !aprint && !xprint )
                    printeroff();
                  else
                    ipadl25();
              } else {                    /*   vice versa ... */
                  cprint = TRUE ;
                  printeron();
              }
            return;
        case K_DUMP:                  /* \Kdump   */
            if ( markmodeflag[mode] != notmarking ) {
                markmode(mode,k);
                return ;
            }
            if ( scrollflag[mode] ) {
                scrollback(mode,k);
                return ;
            }
            x = xprintff; xprintff = 0; /*   Print/Dump current screen */
            prtscreen(mode,1,VscrnGetHeight(mode)-(tt_status[VTERM]?1:0));
            xprintff = x; 
            return;
        case K_PRINTFF:               /* \KprintFF - Print Form Feed */
            prtchar(FF); /* Send formfeed */
            return;
        case K_HANGUP:                /* \Khangup */
            {
                debug( F110,"dokverb","K_HANGUP",0);
                DialerSend( OPT_KERMIT_HANGUP, 0 ) ;
#ifndef NODIAL
                if (mdmhup() < 1)
#endif /* NODIAL */
                    tthang();
            }
            return;
        case K_NULL:                  /* \Knull */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                sendcharduplex('\0',TRUE); 
            return; /*   Send a NUL */
          case K_LBREAK:                /* \Klbreak: */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                ttsndlb(); 
            return;          /*   Send a Long BREAK */
          case K_DEBUG:                 /* \Kdebug */
            flipdebug(); 
            return;        /*   Toggle debugging */
          case K_FLIPSCN:               /* \KflipScn */
            flipscreen(mode);
            VscrnIsDirty(mode);
            return;                     /* Toggle video */
        case K_HOLDSCRN:              /* \KholdScrn */
            if ( holdscreen ) {
                holdscreen = FALSE ;
                restore_status_line();      /* Restore status line */
                VscrnIsDirty(mode) ;
            }
            else {
                save_status_line();         /* Save current status line */
                sprintf(usertext,
                         "SCROLL-LOCK      Press %s to unlock",
                         keyname(vik.holdscrn) );
                helptext[0] = exittext[0] = hostname[0] = NUL;
                VscrnIsDirty(mode);        /* Status line needs to be updated */
                holdscreen = TRUE ;
            }
            return;
        case K_ANSWERBACK:
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
                sendcharsduplex(answerback,strlen(answerback), FALSE) ;
            return ;
        case K_IGNORE:                /* \Kignore */
            return;
#ifdef NETCONN
#ifdef TCPSOCKET
        case K_TN_SAK:
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                do_tn_cmd((CHAR) TN_SAK);
            return;
        case K_TN_GA:                /* TELNET Go Ahead */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                do_tn_cmd((CHAR) TN_GA);
            return;
        case K_TN_AO:                /* TELNET Abort Output */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                do_tn_cmd((CHAR) TN_AO);
            return;
        case K_TN_EL:                /* TELNET Erase Line */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                do_tn_cmd((CHAR) TN_EL);
            return;
        case K_TN_EC:                /* TELNET Erase Character */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                do_tn_cmd((CHAR) TN_EC);
            return;
        case K_TN_AYT:                /* TELNET Are You There */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                do_tn_cmd((CHAR) TN_AYT);
            return;
        case K_TN_IP:                 /* TELNET Interrupt Process */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
              if ( !kbdlocked() )
                do_tn_cmd((CHAR) TN_IP);
            return;
        case K_TN_LOGOUT:             /* TELNET LOGOUT */
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
                if ( !kbdlocked() ) {
                    tn_sopt(DO,TELOPT_LOGOUT);
                    TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
                }
            return;
        case K_TN_NAWS:               /* TELNET NAWS - Send Window Size */
#ifdef  CK_NAWS
            if ( mode == VTERM ||
                 mode == VCMD && activecmd == XXOUT )
                if ( !kbdlocked() ) {
                    TELOPT_SB(TELOPT_NAWS).naws.x = 0;
                    TELOPT_SB(TELOPT_NAWS).naws.y = 0;
                    tn_snaws();
#ifdef RLOGCODE
                    rlog_naws();
#endif /* RLOGCODE */
#ifdef SSHBUILTIN
                    ssh_snaws();
#endif /* SSHBUILTIN */
                }
#endif /* CK_NAWS */
            return;
#endif /* TCPSOCKET */
#endif /* NETCONN */
        case K_PASTE:                 /* Paste clipboard to Host */
            if ( !kbdlocked() )
              CopyClipboardToKbdBuffer(mode) ;
            return;
        case K_CLRSCRN:
            VscrnScroll( mode, UPWARD, 0,
                        VscrnGetHeight(mode)-(tt_status[mode]?2:1),
                        VscrnGetHeight(mode)-(tt_status[mode]?1:0),
                        TRUE,
                        SP, TRUE );
            cleartermscreen(mode) ;    /* Clear the terminal screen */
            VscrnIsDirty(mode);
            return;
        case K_CLRSCROLL:
            clearscrollback(mode, FALSE);
            VscrnIsDirty(mode);
            return;
        case K_SESSION:
            if ( !seslog ) {
                if ( *sesfil )
                  setseslog(1);
                else {
#ifdef KUI
                    char logfile[MAX_PATH+1];
                    if ( !KuiFileDialog("Create Session Log ...","session.log",
                                            logfile,MAX_PATH+1,FALSE, FALSE) )
                        return;
                    setseslog(sesopn( logfile, 0));
#else /* KUI */
                    setseslog(sesopn( "session.log", 0 )); /* create new */
#endif /* KUI */
                }
                if ( !seslog )
                  bleep( BP_FAIL ) ;
            } else {
                setseslog(0);    /* session file.  Therefore, we can continue */
            }
            break;
        case K_LOGON:
            if ( !seslog ) {
                if ( *sesfil )
                  setseslog(1);
                else
                  setseslog(sesopn( "session.log", 0 )); /* create new */
                if ( !seslog )
                  bleep( BP_FAIL ) ;
            } else {
                bleep( BP_WARN ) ;
            }
            return ;
        case K_LOGOFF:
            if ( seslog ) {     /* Unlike CLOSE SESSION we do not close the  */
                setseslog(0);    /* session file.  Therefore, we can continue */
            } else {            /* to append to the file later on.           */
                bleep( BP_WARN ) ;
            }
            return ;

#ifdef PCTERM
        case K_PCTERM:
            setpcterm(!tt_pcterm);
            break;
#endif /* PCTERM */

        case K_AUTODOWN:
#ifndef NOXFER
            if ( !autodl )
                setautodl(1,0);
            else if ( autodl && !adl_ask )
                setautodl(1,1);
            else 
                setautodl(0,0);
#else /* NOXFER */
            bleep( BP_WARN ) ;
#endif /* NOXFER */
            break;

        case K_URLHILT:
            seturlhl(!tt_url_hilite);
            break;

        case K_BYTESIZE:
            if ( cmask == 0177 )
                setcmask(8);
            else
                setcmask(7);
            if (IS97801(tt_type_mode))
                SNI_bitmode((cmask == 0377) ? 8 : 7);
            break;

        case K_SET_BOOK:              /* Bookmark Kverbs */
            bookmarkset(mode);
            return ;

        case K_TERMTYPE:                /* Toggle Terminal Type */
            if ( mode == VTERM )
                  settermtype((tt_type+1)%(TT_MAX+1), 0);
            return ;

        case K_STATUS:          /* Toggle Status-Line Type */
            if ( mode == VTERM )
                setdecssdt((decssdt+1)%3);
            return ;


        case K_KEYCLICK:                /* Toggle Keyclick */
            setkeyclick(!keyclick);
            return ;

        case K_LOGDEBUG:                /* Toggle Debug Log File */
#ifdef DEBUG
            {
                extern int deblog ;
                extern char debfil[] ;
                char * tp ;

                if ( deblog ) {
#ifdef COMMENT
                    doclslog(LOGD);
#else
                    ztime(&tp);
                    debug(F110,"Debug log suspended at",tp,0);
                    deblog = FALSE ;
#endif
                }
                else {
                    if ( debfil && *debfil ) {
                        deblog = TRUE ;
                        ztime(&tp);
                        debug(F110,"Debug log resumed at",tp,0);
                    }
                    else
                        deblog = debopn("debug.log",0);
                }
            }
#endif /* DEBUG */
            return ;

        case K_FNKEYS:                  /* Display Function Key Labels */
            if ( mode == VTERM ) {
                fkeypopup(mode);
            }
            return;

#ifdef OS2MOUSE
        case K_CURSOR_URL:
            mouseurl(mode,vscrn[mode].cursor.y,vscrn[mode].cursor.x);
            break;
#endif /* OS2MOUSE */

        case K_FOCUS_IN:
#ifdef KUI
            if (transmit_focus_change && mode == VTERM) {
                sendescseq("[I");
            }
#endif /* KUI */
            break;
        case K_FOCUS_OUT:
#ifdef KUI
            if (transmit_focus_change && mode == VTERM) {
                sendescseq("[O");
            }
#endif /* KUI */
            break;

        default:                        /* None of the above */
            return;                     /* Ignore this key and return. */
        }
    }

    /* Capture all kverbs that must go to mark mode */

    if (k >= K_MARK_MIN && k <= K_MARK_MAX ||
        ( markmodeflag[mode] != notmarking &&
            (k >= K_ROLLMIN && k <= K_ROLLMAX ||
            k >= K_ARR_MIN && k <= K_ARR_MAX ))) {
        /* mark mode goes here */
        markmode(mode,k);
        return ;
    }
    if (k >= K_ROLLMIN && k <= K_ROLLMAX ) { /* Screen rollback... */
        scrollback(mode,k);
        return;
    }

    if ( k >= K_LFONE && k <= K_RTALL ) {       /* Horizontal Scrolling */
        switch ( k ) {
        case K_LFONE:
            if ( vscrn[mode].hscroll == 0 )
                bleep(BP_WARN);
            else if ( vscrn[mode].hscroll > 0 )
                vscrn[mode].hscroll -= 1 ;
            break;
        case K_LFPAGE:
            if ( vscrn[mode].hscroll == 0 )
                bleep(BP_WARN);
            else if ( vscrn[mode].hscroll > 8 )
                vscrn[mode].hscroll -= 8 ;
            else
                vscrn[mode].hscroll = 0 ;
            break;
        case K_LFALL:
            if ( vscrn[mode].hscroll == 0 )
                bleep(BP_WARN);
            else if ( vscrn[mode].hscroll > 0 )
                vscrn[mode].hscroll = 0 ;
            break;
        case K_RTONE:
            if ( vscrn[mode].hscroll == MAXTERMCOL-pwidth )
                bleep(BP_WARN);
            else if ( vscrn[mode].hscroll < MAXTERMCOL-pwidth )
                vscrn[mode].hscroll += 1 ;
            break;
        case K_RTPAGE:
            if ( vscrn[mode].hscroll == MAXTERMCOL-pwidth )
                bleep(BP_WARN);
            else if ( vscrn[mode].hscroll < MAXTERMCOL-pwidth-8 )
                vscrn[mode].hscroll += 8 ;
            else
                vscrn[mode].hscroll = MAXTERMCOL-pwidth ;
            break;
        case K_RTALL:
            if ( vscrn[mode].hscroll == MAXTERMCOL-pwidth )
                bleep(BP_WARN);
            else if ( vscrn[mode].hscroll < MAXTERMCOL-pwidth )
                vscrn[mode].hscroll = MAXTERMCOL-pwidth ;
            break;
        }
        VscrnIsDirty(mode);
        return;
    }

#ifdef OS2MOUSE
    if (k >= K_MOUSE_MIN && k <= K_MOUSE_MAX) {
        /* mouse verbs cannot be assigned to keys */
        bleep(BP_FAIL);
        return ;
    }
#endif /* OS2MOUSE */

    if ( !kbdlocked() ) {
        if ( mode == VTERM ||
             mode == VCMD && activecmd == XXOUT ) {

            /* Handle arrow keys */
            if (k >= K_ARR_MIN && k <= K_ARR_MAX) {
                if ( ISDG200( tt_type_mode ) ) {
                    /* Data General */
                    extern int dgunix;

                    switch ( k ) {
                    case K_UPARR:
                        if ( dgunix ) {
                            if ( udkfkeys[K_DGUPARR-K_DGF01+25] )
                                sendcharsduplex(udkfkeys[K_DGUPARR - K_DGF01+25],
                                                 strlen(udkfkeys[K_DGUPARR - K_DGF01+25]),
                                                 TRUE);
                            else
                                sendcharsduplex("\036PA",3,TRUE);
                        }
                        else {
                            if ( udkfkeys[K_DGUPARR-K_DGF01] )
                                sendcharsduplex(udkfkeys[K_DGUPARR - K_DGF01],
                                                 strlen(udkfkeys[K_DGUPARR - K_DGF01]),
                                                 TRUE);
                            else
                            sendcharduplex(ETB,TRUE);
                        }
                        break;
                    case K_RTARR:
                        if ( dgunix ) {
                            if ( udkfkeys[K_DGRTARR-K_DGF01+25] )
                                sendcharsduplex(udkfkeys[K_DGRTARR - K_DGF01+25],
                                                 strlen(udkfkeys[K_DGRTARR - K_DGF01+25]),
                                                 TRUE);
                            else
                            sendcharsduplex("\036PC",3,TRUE);
                        }
                        else {
                            if ( udkfkeys[K_DGRTARR-K_DGF01] )
                                sendcharsduplex(udkfkeys[K_DGRTARR - K_DGF01],
                                                 strlen(udkfkeys[K_DGRTARR - K_DGF01]),
                                                 TRUE);
                            else
                            sendcharduplex(CAN,TRUE);
                        }
                        break;
                    case K_LFARR:
                        if ( dgunix ) {
                            if ( udkfkeys[K_DGLFARR-K_DGF01+25] )
                                sendcharsduplex(udkfkeys[K_DGLFARR - K_DGF01+25],
                                                 strlen(udkfkeys[K_DGLFARR - K_DGF01+25]),
                                                 TRUE);
                            else
                            sendcharsduplex("\036PD",3,TRUE);
                        }
                        else {
                            if ( udkfkeys[K_DGLFARR-K_DGF01] )
                                sendcharsduplex(udkfkeys[K_DGLFARR - K_DGF01],
                                                 strlen(udkfkeys[K_DGLFARR - K_DGF01]),
                                                 TRUE);
                            else
                            sendcharduplex(XEM,TRUE);
                        }
                        break;
                    case K_DNARR:
                        if ( dgunix ) {
                            if ( udkfkeys[K_DGDNARR-K_DGF01+25] )
                                sendcharsduplex(udkfkeys[K_DGDNARR - K_DGF01+25],
                                                 strlen(udkfkeys[K_DGDNARR - K_DGF01+25]),
                                                 TRUE);
                            else
                            sendcharsduplex("\036PB",3,TRUE);
                        }
                        else {
                            if ( udkfkeys[K_DGDNARR-K_DGF01] )
                                sendcharsduplex(udkfkeys[K_DGDNARR - K_DGF01],
                                                 strlen(udkfkeys[K_DGDNARR - K_DGF01]),
                                                 TRUE);
                            else
                            sendcharduplex(SUB,TRUE);
                        }
                        break;
                    }
                }
                else if ( ISQNX( tt_type_mode ) ) {
                    /* QNX */
                    char buf[3] ;
                    switch ( k ) {
                    case K_UPARR:
                        sprintf(buf,"\377\241");
                        break;
                    case K_RTARR:
                        sprintf(buf,"\377\246");
                        break;
                    case K_LFARR:
                        sprintf(buf,"\377\244");
                        break;
                    case K_DNARR:
                        sprintf(buf,"\377\251");
                        break;
                    }
                    sendcharsduplex(buf,2,TRUE);
                }
                else if ( ISHP( tt_type_mode ) ||
                          ISIBM31(tt_type_mode)) {
                    /* HP2621A || IBM 31xx */
                    char buf[3] ;
                    switch ( k ) {
                    case K_UPARR:
                        sprintf(buf,"%cA",ESC);
                        break;
                    case K_RTARR:
                        sprintf(buf,"%cC",ESC);
                        break;
                    case K_LFARR:
                        sprintf(buf,"%cD",ESC);
                        break;
                    case K_DNARR:
                        sprintf(buf,"%cB",ESC);
                        break;
                    }
                    sendcharsduplex(buf,2,TRUE);
                }
                else if ( ISHZL( tt_type_mode ) ) {
                    /* Hazeltine */
                    switch ( k ) {
                    case K_UPARR:
                        sendcharsduplex("~\x0C",2,TRUE);
                        break;
                    case K_RTARR:
                        sendcharduplex(DLE,TRUE);
                        break;
                    case K_LFARR:
                        sendcharduplex(BS,TRUE);
                        break;
                    case K_DNARR:
                        sendcharsduplex("~\x0B",2,TRUE);
                        break;
                    }
                }
                else if ( ISVC( tt_type_mode ) ) {
                    /* Victor Craig */
                    switch ( k ) {
                    case K_UPARR:
                        sendcharduplex(SUB,TRUE);
                        break;
                    case K_RTARR:
                        sendcharduplex(NAK,TRUE);
                        break;
                    case K_LFARR:
                        sendcharduplex(BS,TRUE);
                        break;
                    case K_DNARR:
                        sendcharduplex(LF,TRUE);
                        break;
                    }
                }
                else if ( ISREGENT25( tt_type_mode ) ) {
                    /* ADDS Regent 25 */
                    switch ( k ) {
                    case K_UPARR:
                        sendcharduplex(SUB,TRUE);
                        break;
                    case K_RTARR:
                        sendcharduplex(ACK,TRUE);
                        break;
                    case K_LFARR:
                        sendcharduplex(NAK,TRUE);
                        break;
                    case K_DNARR:
                        sendcharduplex(LF,TRUE);
                        break;
                    }
                }
                else if ( ISWYSE( tt_type_mode ) ) {
                    switch ( k ) {
                    case K_UPARR:
                        if ( udkfkeys[K_WYUPARR-K_WYF01] )
                            sendcharsduplex(udkfkeys[K_WYUPARR - K_WYF01],
                                       strlen(udkfkeys[K_WYUPARR - K_WYF01]),
                                             TRUE);
                        else
                            sendcharduplex(VT,TRUE);
                        break;
                    case K_RTARR:
                        if ( udkfkeys[K_WYRTARR-K_WYF01] )
                            sendcharsduplex(udkfkeys[K_WYRTARR - K_WYF01],
                                       strlen(udkfkeys[K_WYRTARR - K_WYF01]),
                                             TRUE);
                        else
                            sendcharduplex(FF,TRUE);
                        break;
                    case K_LFARR:
                        if ( udkfkeys[K_WYLFARR-K_WYF01] )
                            sendcharsduplex(udkfkeys[K_WYLFARR - K_WYF01],
                                       strlen(udkfkeys[K_WYLFARR - K_WYF01]),
                                             TRUE);
                        else
                            sendcharduplex(BS,TRUE);
                        break;
                    case K_DNARR:
                        if ( udkfkeys[K_WYDNARR-K_WYF01] )
                            sendcharsduplex(udkfkeys[K_WYDNARR - K_WYF01],
                                       strlen(udkfkeys[K_WYDNARR - K_WYF01]),
                                             TRUE);
                        else
                            sendcharduplex(LF,TRUE);
                        break;
                    }
                }
                else if ( ISTVI( tt_type_mode ) ) {
                    switch ( k ) {
                    case K_UPARR:
                        if ( udkfkeys[K_TVIUPARR-K_TVIF01] )
                            sendcharsduplex(udkfkeys[K_TVIUPARR - K_TVIF01],
                                       strlen(udkfkeys[K_TVIUPARR - K_TVIF01]),
                                             TRUE);
                        else
                            sendcharduplex(DLE,TRUE);
                        break;
                    case K_RTARR:
                        if ( udkfkeys[K_TVIRTARR-K_TVIF01] )
                            sendcharsduplex(udkfkeys[K_TVIRTARR - K_TVIF01],
                                       strlen(udkfkeys[K_TVIRTARR - K_TVIF01]),
                                             TRUE);
                        else
                            sendcharduplex(ACK,TRUE);
                        break;
                    case K_LFARR:
                        if ( udkfkeys[K_TVILFARR-K_TVIF01] )
                            sendcharsduplex(udkfkeys[K_TVILFARR - K_TVIF01],
                                       strlen(udkfkeys[K_TVILFARR - K_TVIF01]),
                                             TRUE);
                        else
                            sendcharduplex(STX,TRUE);
                        break;
                    case K_DNARR:
                        if ( udkfkeys[K_TVIDNARR-K_TVIF01] )
                            sendcharsduplex(udkfkeys[K_TVIDNARR - K_TVIF01],
                                       strlen(udkfkeys[K_TVIDNARR - K_TVIF01]),
                                             TRUE);
                        else
                            sendcharduplex(SO,TRUE);
                        break;
                    }
                }
                else if ( IS97801(tt_type_mode) ) {
                    switch ( k ) {
                    case K_UPARR:
                        if ( udkfkeys[K_SNI_CURSOR_UP-K_SNI_F01] )
                            sendcharsduplex(udkfkeys[K_SNI_CURSOR_UP - K_SNI_F01],
                                       strlen(udkfkeys[K_SNI_CURSOR_UP - K_SNI_F01]),
                                             TRUE);
                        else
                            sendcharsduplex("\033[A",3,TRUE);
                        break;
                    case K_RTARR:
                        if ( udkfkeys[K_SNI_CURSOR_RIGHT-K_SNI_F01] )
                            sendcharsduplex(udkfkeys[K_SNI_CURSOR_RIGHT - K_SNI_F01],
                                       strlen(udkfkeys[K_SNI_CURSOR_RIGHT - K_SNI_F01]),
                                             TRUE);
                        else
                            sendcharsduplex("\033[C",3,TRUE);
                        break;
                    case K_LFARR:
                        if ( udkfkeys[K_SNI_CURSOR_LEFT-K_SNI_F01] )
                            sendcharsduplex(udkfkeys[K_SNI_CURSOR_LEFT - K_SNI_F01],
                                       strlen(udkfkeys[K_SNI_CURSOR_LEFT - K_SNI_F01]),
                                             TRUE);
                        else
                            sendcharsduplex("\033[D",3,TRUE);
                        break;
                    case K_DNARR:
                        if ( udkfkeys[K_SNI_CURSOR_DOWN-K_SNI_F01] )
                            sendcharsduplex(udkfkeys[K_SNI_CURSOR_DOWN - K_SNI_F01],
                                       strlen(udkfkeys[K_SNI_CURSOR_DOWN - K_SNI_F01]),
                                             TRUE);
                        else
                            sendcharsduplex("\033[B",3,TRUE);
                        break;
                    }
                }
                else {
                    /* DEC arrow (cursor) keys */
                    if (ISVT100(tt_type_mode) ||
                         ISANSI(tt_type_mode) ||
                         ISQANSI(tt_type_mode) ||
                         ISBEOS(tt_type_mode) ||
                        ISHFT(tt_type_mode))
                        sprintf(escbuf,"%c%c",( (tt_arrow == TTK_APPL) ? 'O' : '[' ),
                                 'A' + (k - K_UPARR));
                    else
                        sprintf(escbuf,"%c", 'A' + (k - K_UPARR));
                    sendescseq(escbuf);
                }
                return;
            }

            if (k >= K_PF1 && k <= K_PF4) { /* DEC PF keys */
                char *p = escbuf;
                if (ISVT100(tt_type_mode)) /* SS3 P..S for VT100 & above */
                  *p++ = 'O';
                *p++ = 'P' + (k - K_PF1);   /* or just ESC P..S for VT52 */
                *p = NUL;
                sendescseq(escbuf);
                return;
            }

            if (k >= K_KP0 && k <= K_KP9) { /* DEC numeric keypad keys */
                if (tt_keypad == TTK_NORM)  /* Keypad in numeric mode */
                  sendcharduplex((CHAR) ('0' + (CHAR) (k - K_KP0)),TRUE);
                else {                      /* Application mode */
                    int dup_sav = duplex;
                    duplex = 0;
                    sprintf(escbuf,
                        "%c%c",
                        (ISVT100(tt_type_mode) ? 'O' : '?'),
                        ('p' + (k - K_KP0))
                        );
                    sendescseq(escbuf);
                    duplex = dup_sav;
                }
                return;
            }

            if (k >= K_KPCOMA && k <= K_KPDOT) { /* DEC keypad punctuation keys */
                if (tt_keypad == TTK_NORM)  /* Keypad in numeric mode */
                  sendcharduplex((CHAR) (',' + (CHAR) (k - K_KPCOMA)),TRUE); /*  */
                else {                      /* Keypad in application mode */
                    int dup_sav = duplex;
                    duplex = 0;
                    sprintf(escbuf,
                             "%c%c",
                             (ISVT100(tt_type_mode) ? 'O' : '?'),
                             ('l' + (k - K_KPCOMA))
                             );
                    sendescseq(escbuf);
                    duplex = dup_sav;
                }
                return;
            }

            if (k == K_KPENTER) {           /* DEC keypad Enter key */
                if (tt_keypad == TTK_NORM) { /* Keypad in numeric mode */
                    sendcharduplex('\015',TRUE);  /* Send CR */
                    if (tnlm)
                      sendcharduplex('\012',TRUE); /* Newline mode, send LF too */
                } else {                    /* Keypad in application mode */
                    int dup_sav = duplex;
                    duplex = 0;
                    sprintf(escbuf,
                             "%cM",
                             (ISVT100(tt_type_mode) ? 'O' : '?')
                             );
                    sendescseq(escbuf);
                    duplex = dup_sav;
                }
                return;
            }

            if (k >= K_DECFIND && k <= K_DECHOME) { /* DEC editing keypad keys */
                int dup_sav = duplex;
                duplex = 0;
                if (ISVT220(tt_type_mode)) /* VT220 and above */
                  sendescseq(ekeys[k - K_DECFIND]);
                else bleep(BP_WARN);
                duplex = dup_sav;
                return;
            }

            if (k >= K_DECF1 && k <= K_DECF20) { /* DEC top-rank function keys */
                if (ISVT220(tt_type_mode)) { /* VT220 and above */
                    int dup_sav = duplex;
                    duplex =0;
                    sendescseq(fkeys[k - K_DECF1]);
                    duplex = dup_sav;
                    return;
                } else {                    /* VT102 or lower */
                    switch (k) {
                    case K_DECF11:
                        sendcharduplex(ESC,TRUE); return;
                    case K_DECF12:
                        sendcharduplex(BS,TRUE); return;
                    case K_DECF13:
                        sendcharduplex(LF,TRUE); return;
                    default:
                        bleep(BP_WARN);
                        return;
                    }
                }
            }

            if (k >= K_UDKF1 && k <= K_UDKF20) { /* User-Defined Keys */
                if (ISVT220(tt_type_mode)) { /* VT220 and above */
                    if ( udkfkeys[k-K_UDKF1] )
                      sendcharsduplex(udkfkeys[k - K_UDKF1],
                                 strlen(udkfkeys[k - K_UDKF1]),TRUE);

                }
                else {
                    bleep( BP_WARN );
                }
                return;
            }

            if ( k >= K_ANSIF01 && k <= K_ANSIF61 ) { /* ANSI FN Keys */
                if ( ISUNIXCON(tt_type_mode) ) {
                    if ( udkfkeys[k-K_ANSIF01] )
                      sendcharsduplex(udkfkeys[k-K_ANSIF01],
                                 strlen(udkfkeys[k-K_ANSIF01]),TRUE) ;
                }
                else {
                    bleep( BP_WARN ) ;
                }
                return ;
            }

            if ( k >= K_WYF01 && k <= K_WYSSEND ) {    /* WYSE FN Keys */
                if ( ISWYSE(tt_type_mode) ) {
                    if ( udkfkeys[k-K_WYF01] )
                        sendcharsduplex(udkfkeys[k-K_WYF01],
                                   strlen(udkfkeys[k-K_WYF01]),TRUE);
                }
                else
                    bleep( BP_WARN ) ;
                return ;
            }

            if ( k >= K_TVIF01 && k <= K_TVIPRTSCN ||
                        k == K_TVISEND || k == K_TVISSEND) {    /* TVI FN Keys */
                if ( ISTVI(tt_type_mode) ) {
                    if ( udkfkeys[k-K_TVIF01] )
                        sendcharsduplex(udkfkeys[k-K_TVIF01],
                                   strlen(udkfkeys[k-K_TVIF01]),TRUE);
                }
                else
                    bleep( BP_WARN ) ;
                return ;
            }

            if ( k >= K_HPF01 && k <= K_HPENTER ) {     /* HP FN Keys */
                if ( ISHP(tt_type_mode) ) {
                    if ( udkfkeys[k-K_HPF01] )
                        sendcharsduplex(udkfkeys[k-K_HPF01],
                                   strlen(udkfkeys[k-K_HPF01]),TRUE);
                }
                else
                    bleep( BP_WARN ) ;
                return ;
            }

            if ( k >= K_DGF01 && k <= K_DGSHOME ) {     /* DG FN Keys */
                if ( ISDG200(tt_type_mode) ) {
                    extern int dgunix;
                    if ( k <= K_DGCSF15 || ! dgunix ) {
                        if ( udkfkeys[k-K_DGF01] )
                        sendcharsduplex(udkfkeys[k-K_DGF01],
                                   strlen(udkfkeys[k-K_DGF01]),TRUE);
                    }
                    else {
                        if ( udkfkeys[k-K_DGF01+25] )
                        sendcharsduplex(udkfkeys[k-K_DGF01+25],
                                   strlen(udkfkeys[k-K_DGF01+25]),TRUE);
                    }
                }
                else
                    bleep( BP_WARN );
                return;
            }

            if ( k >= K_SNI_MIN && k <= K_SNI_MAX ) {   /* SNI FN Keys */
                if ( IS97801(tt_type_mode) ) {
                    if ( k == K_SNI_CH_CODE ) {
                        if ( sni_bitmode == 8 && !sni_chcode_8 ||
                             sni_bitmode == 7 && !sni_chcode_7 )
                            bleep(BP_WARN);
                        else {
                            SNI_chcode(!sni_chcode);
                            if ( sni_chcode )
                                printf("SNI Ch.Code is ON\n");
                            else
                                printf("SNI Ch.Code is OFF\n");
                        }
                    } else {
                        if ( udkfkeys[k-K_SNI_MIN] )
                            sendcharsduplex(udkfkeys[k-K_SNI_MIN],
                                             strlen(udkfkeys[k-K_SNI_MIN]),TRUE);
                    }
                }
                else
                    bleep( BP_WARN );
                return;
            }

            if ( k >= K_BA80_MIN && k <= K_BA80_MAX ) { /* SNI FN Keys */
                if ( ISBA80(tt_type_mode) ) {
                    if ( udkfkeys[k-K_BA80_MIN] )
                        sendcharsduplex(udkfkeys[k-K_BA80_MIN],
                                   strlen(udkfkeys[k-K_BA80_MIN]),TRUE);
                }
                else
                    bleep( BP_WARN );
                return;
            }

            if ( k >= K_I31_MIN && k <= K_I31_MAX ) {   /* IBM 31xx FN Keys */
                if ( ISIBM31(tt_type_mode) ) {
                    if ( udkfkeys[k-K_I31_MIN] )
                        sendcharsduplex(udkfkeys[k-K_I31_MIN],
                                   strlen(udkfkeys[k-K_I31_MIN]),TRUE);
                }
                else
                    bleep( BP_WARN );
                return;
            }

            if ( k >= K_SUN_MIN && k <= K_SUN_MAX ) {   /* SUN Keys */
                if ( ISSUN(tt_type_mode) ) {
                    if ( udkfkeys[k-K_SUN_MIN] )
                        sendcharsduplex(udkfkeys[k-K_SUN_MIN],
                                   strlen(udkfkeys[k-K_SUN_MIN]),TRUE);
                }
                else
                    bleep( BP_WARN );
                return;
            }

            if ( k == K_EMACS_OVER && tt_kb_mode == KBM_EM )
                sendescseq("Xoverwrite\r") ;
        }

        if (k == K_COMPOSE) {           /* Compose key */
            dokcompose(mode, 0) ;
            return;
        }

        if (k == K_C_UNI16) {           /* Compose key */
            dokcompose(mode, 1) ;
            return;
        }

        if ( mode == VTERM ) {
            if (k == K_KB_HEB) {            /* Hebrew keyboard support... */
                if ( tt_kb_mode == KBM_HE )
                    set_kb_mode(KBM_EN) ;
                else
                    set_kb_mode(KBM_HE) ;
                ipadl25();                      /* Update the status line */
                return;
            }

            if (k == K_KB_RUS) {            /* Russian keyboard support... */
                if ( tt_kb_mode == KBM_RU )
                    set_kb_mode(KBM_EN) ;
                else
                    set_kb_mode(KBM_RU) ;
                ipadl25();                      /* Update the status line */
                return;
            }

            if ( k == K_KB_EMA ) {      /* Emacs keyboard support */
                if ( tt_kb_mode == KBM_EM )
                    set_kb_mode(KBM_EN) ;
                else
                    set_kb_mode(KBM_EM) ;
                ipadl25();                      /* Update the status line */
                return ;
            }

            if ( k == K_KB_WP ) {       /* WP5.1 keyboard support */
                if ( tt_kb_mode == KBM_WP )
                    set_kb_mode(KBM_EN);
                else
                    set_kb_mode(KBM_WP);
                ipadl25();                      /* Update the status line */
                return ;
            }
            if (k == K_KB_ENG) {            /* English too... */
                if ( tt_kb_mode != KBM_EN ) {
                    set_kb_mode(KBM_EN);
                    ipadl25();                  /* Update the status line */
                }
                return;
            }
        }

    } /* !kbdlocked() */
}
#endif /* NOKVERBS */

/*  S E N D K E Y D E F  --  Send key definition  */

void
sendkeydef(unsigned char *s, int no_xlate ) {
#ifndef NOKVERBS
    int x, y, brace = 0;
    char * p, * b;
#define K_BUFLEN 30
    char kbuf[K_BUFLEN + 1];            /* Key verb name buffer */
#define SEND_BUFLEN 255
#define sendbufd(x) { sendbuf[sendndx++] = x ; if (sendndx == SEND_BUFLEN) { sendcharsduplex(s,SEND_BUFLEN,no_xlate); sendndx = 0 ;}}
    char sendbuf[SEND_BUFLEN +1] ;
    int  sendndx = 0 ;
#endif /* NOKVERBS */

#ifdef NOKVERBS
    sendcharsduplex(s, strlen(s), no_xlate); /* Send the entire string literally. */
#else   /* \Kverb support ... */
    for ( ; *s; s++ ) {                 /* Go through the string */

        if (*s != CMDQ) {               /* Normal character */
            sendbufd(*s) ;
            continue;                   /* Get next, etc. */
        }
        b = s++;                        /* Get next character */
        if (!*s) {
            sendbufd(CMDQ) ;            /* Send the CMDQ char */
            goto exit_sendkeydef ;      /* and then exit */
        }
        if (*s == '{') {                /* Opening brace? */
            brace++;                    /* Remember */
            s++;                        /* Go to next character */
            if (!*s) {
                goto exit_sendkeydef ;
            }
        }
        if (*s == 'K' || *s == 'k') {   /* Have K verb? */
            s++;
            if (*s == '{') {                /* Opening brace? */
                brace++;                  /* Remember */
                s++;                        /* Go to next character */
                if (!*s) {
                    goto exit_sendkeydef ;
                }
            } else if (!*s) {
                goto exit_sendkeydef ;
            }

/*
  We assume that the verb name is {braced}, or it extends to the end of the
  string, s, or it ends with a space, control character, or backslash.
*/
            p = kbuf;                   /* Copy verb name into local buffer */
            x = 0;
            while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
                if (brace && *s == '}') {
                    if (brace == 1)
                        break;
                    brace--;
                    s++;
                    continue;
                }
                *p++ = *s++;
            }
            if (*s && !brace)           /* If we broke because of \, etc, */
                s--;                    /*  back up so we get another look. */
            brace = 0;
            *p = NUL;                   /* Terminate. */
            p = kbuf;                   /* Point back to beginning */
            debug(F110,"sendkeydef kverb",p,0);
            y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
            debug(F101,"sendkeydef lookup",0,y);
            if (y > -1) {
                if ( sendndx ) {
                    sendcharsduplex( sendbuf, sendndx, no_xlate ) ;
                    sendndx = 0 ;
                }
                dokverb(VTERM,y) ;
#ifndef NOSPL
            } else {                    /* Is it a macro? */
                y = mxlook(mactab,p,nmac);
                if (y > -1) {
                    keymac = 1;         /* Flag for key macro active */
                    keymacx = y;        /* Key macro index */
                    keydefptr = s;      /* Where to resume next time */
                    debug(F111,"sendkeydef mxlook",keydefptr,y);
                    SetConnectMode(0,CSX_MACRO); /* Leave CONNECT mode */
                }
#endif /* NOSPL */
            }
        } else if (*s == 'V' || *s == 'v') { /* Have \v(xxx)? */
            s++;                        /* Next char */
            if (!*s)
                goto exit_sendkeydef ;
            if (*s != '(') {            /* Should be left paren */
                sendbufd(CMDQ) ;
                sendbufd(*s) ;
                continue;
            }
            b = s - 1;                  /* Save my place */
            s++;                        /* Point past paren */
            p = kbuf;                   /* Point to word buffer */
            x = 0;                      /* Copy verb into it */
            while ((x++ < K_BUFLEN) && (*s > SP) && (*s != ')'))
                *p++ = *s++;
            *p = NUL;
            if (*s != ')') {            /* Have terminating paren? */
                                        /* No, send this literally */
                sendbufd(CMDQ) ;
                s = b;
                continue;
            } else {
                p = kbuf;               /* Point back to beginning */
                debug(F110,"sendkeydef v(verb)",p,0);
                p = nvlook(p);          /* Look it up. */
                if (!p)                 /* Not found, */
                    continue;           /* continue silently. */
                while (*p) {            /* Send it. */
                    sendbufd(*p++) ;
                }
                if (!*s)
                    goto exit_sendkeydef ;
            }
        } else if (*s == CMDQ) {        /* A Quoted CMDQ */
            sendbufd(CMDQ);
        } else {                        /* Not \K, \{K, \V, or \\ */
                                        /* Back up and send backslash, */
            sendbufd(CMDQ) ;
            if (brace) {                /* and maybe a left brace, */
                sendbufd('{') ;
                brace = 0;
            }
            if (*s) /* and this char literally. */
                sendbufd(*s) ;
        }
        if (!*s) {
            keydefptr = NULL;
            return;
        }
    }
  exit_sendkeydef:
    if ( sendndx ) {
        sendcharsduplex( sendbuf, sendndx, no_xlate ) ;
        sendndx = 0 ;
    }
    keydefptr = NULL;
#undef sendbufd
#endif /* NOKVERBS */
}

void
scrollstatusline( void )
{
#ifndef NOKVERBS
    /* Build a special status line for scrollback mode */
    /* Usertext field updated dynamicly in line25()    */

    if ( markmodeflag[VTERM] == notmarking ) {
        if (vik.upscn > 255 && keyname(vik.upscn)) {
                strncpy(helptext, keyname(vik.upscn), 20);
            if (vik.dnscn > 255 && keyname(vik.dnscn)) {
                ckstrncat(helptext,"/",HLPTXTLEN);
                ckstrncat(helptext,keyname(vik.dnscn),HLPTXTLEN);
            }
        }
        else
            ckstrncpy(helptext, "\\KupScn,\\KdnScn",HLPTXTLEN);
        }
    else {
        sprintf(helptext, "%c,%c,%c,%c\0",27,24,25,26);
    }

    if ((vik.help > 255) &&
         (keyname(vik.help)) &&
         ((HSTNAMLEN - 6 - (int)strlen(keyname(vik.help))) > 0)) {
        sprintf(hostname, "Help: %s", keyname(vik.help));
    }
    else if (vik.homscn > 255 && keyname(vik.homscn)) {
            strcpy(hostname, keyname(vik.homscn));
        if (vik.endscn > 255 && keyname(vik.endscn)) {
            ckstrncat(hostname,"/",HSTNAMLEN);
            ckstrncat(hostname,keyname(vik.endscn),HSTNAMLEN);
        }
    }
    else
        ckstrncpy(hostname, "\\KhomScn,\\KendScn",HSTNAMLEN);

    helptext[0] = '\0';
    exittext[0] = '\0';
    /* filetext[0] = '\0'; */
#endif /* NOKVERBS */
}

/* Mark mode - this replaces most of the Mouse Functions */

void
markmode( BYTE vmode, int k )
{
#ifndef NOKVERBS
    static int rollstate[VNUM]={0,0,0,0},
               scrollstate[VNUM]={0,0,0,0};
    static KEY savekeys[8]={0,0,0,0,0,0,0,0};
    static MACRO savemacros[8]={0,0,0,0,0,0,0,0};

    if ( k != K_MARK_START && markmodeflag[vmode] == notmarking )
    {
       switch( k )
       {
       case K_BACKSRCH:
          markmode( vmode, K_MARK_START ) ;
          if ( search( vmode, FALSE, TRUE ) )
          {
             k = K_MARK_START ;
             break;
          }
          else
          {
             markmode( vmode, K_MARK_CANCEL ) ;
             bleep( BP_FAIL ) ;
             return;
          }
       case K_BACKNEXT:
          markmode( vmode, K_MARK_START ) ;
          if ( search( vmode, FALSE, FALSE ) )
          {
             k = K_MARK_START ;
             break;
          }
          else
          {
             markmode( vmode, K_MARK_CANCEL ) ;
             bleep( BP_FAIL ) ;
             return;
          }
       case K_FWDSRCH:
          markmode( vmode, K_MARK_START ) ;
          if ( search( vmode, TRUE, TRUE ) )
          {
             k = K_MARK_START ;
             break;
          }
          else
          {
             markmode( vmode, K_MARK_CANCEL ) ;
             bleep( BP_FAIL ) ;
             return;
          }
       case K_FWDNEXT:
          markmode( vmode, K_MARK_START ) ;
          if ( search( vmode, TRUE, FALSE ) )
          {
             k = K_MARK_START ;
             break;
          }
          else
          {
             markmode( vmode, K_MARK_CANCEL ) ;
             bleep( BP_FAIL ) ;
             return;
          }

       case K_MARK_CANCEL:
           return;

       default:
          bleep( BP_WARN ) ;
          return ;
       }
    }

    if ( markmodeflag[vmode] == notmarking ) {
        /* Save Macro and Keymap settings for Arrow keys */
        savemacros[0] = macrotab[KEY_SCAN | KEY_ENHANCED | 38] ;     /* Up Arrow    Gray */
        savemacros[1] = macrotab[KEY_SCAN | 38               ] ;     /* Up Arrow    Numeric */
        savemacros[2] = macrotab[KEY_SCAN | KEY_ENHANCED | 37] ;     /* Left Arrow  Gray */
        savemacros[3] = macrotab[KEY_SCAN | 37               ] ;     /* Left Arrow  Numeric*/
        savemacros[4] = macrotab[KEY_SCAN | KEY_ENHANCED | 39] ;     /* Right Arrow Gray */
        savemacros[5] = macrotab[KEY_SCAN | 39               ] ;     /* Right Arrow Numeric */
        savemacros[6] = macrotab[KEY_SCAN | KEY_ENHANCED | 40] ;     /* Down Arrow  Gray */
        savemacros[7] = macrotab[KEY_SCAN | 40               ] ;     /* Down Arrow  Numeric */

        savekeys[0] = keymap[KEY_SCAN | KEY_ENHANCED | 38] ;         /* Up Arrow    Gray */
        savekeys[1] = keymap[KEY_SCAN | 38               ] ;         /* Up Arrow    Numeric */
        savekeys[2] = keymap[KEY_SCAN | KEY_ENHANCED | 37] ;         /* Left Arrow  Gray */
        savekeys[3] = keymap[KEY_SCAN | 37               ] ;         /* Left Arrow  Numeric*/
        savekeys[4] = keymap[KEY_SCAN | KEY_ENHANCED | 39] ;         /* Right Arrow Gray */
        savekeys[5] = keymap[KEY_SCAN | 39               ] ;         /* Right Arrow Numeric */
        savekeys[6] = keymap[KEY_SCAN | KEY_ENHANCED | 40] ;         /* Down Arrow  Gray */
        savekeys[7] = keymap[KEY_SCAN | 40               ] ;         /* Down Arrow  Numeric */

        macrotab[KEY_SCAN | KEY_ENHANCED | 38] = NULL ;              /* Up Arrow    Gray */
        macrotab[KEY_SCAN | 38               ] = NULL ;              /* Up Arrow    Numeric */
        macrotab[KEY_SCAN | KEY_ENHANCED | 37] = NULL ;              /* Left Arrow  Gray */
        macrotab[KEY_SCAN | 37               ] = NULL ;              /* Left Arrow  Numeric*/
        macrotab[KEY_SCAN | KEY_ENHANCED | 39] = NULL ;              /* Right Arrow Gray */
        macrotab[KEY_SCAN | 39               ] = NULL ;              /* Right Arrow Numeric */
        macrotab[KEY_SCAN | KEY_ENHANCED | 40] = NULL ;              /* Down Arrow  Gray */
        macrotab[KEY_SCAN | 40               ] = NULL ;              /* Down Arrow  Numeric */

        keymap[KEY_SCAN | KEY_ENHANCED | 38] = F_KVERB | K_UPARR;       /* Up Arrow    Gray */
        keymap[KEY_SCAN | 38               ] = F_KVERB | K_UPARR;       /* Up Arrow    Numeric */
        keymap[KEY_SCAN | KEY_ENHANCED | 37] = F_KVERB | K_LFARR;       /* Left Arrow  Gray */
        keymap[KEY_SCAN | 37               ] = F_KVERB | K_LFARR;       /* Left Arrow  Numeric*/
        keymap[KEY_SCAN | KEY_ENHANCED | 39] = F_KVERB | K_RTARR;       /* Right Arrow Gray */
        keymap[KEY_SCAN | 39               ] = F_KVERB | K_RTARR;       /* Right Arrow Numeric */
        keymap[KEY_SCAN | KEY_ENHANCED | 40] = F_KVERB | K_DNARR;       /* Down Arrow  Gray */
        keymap[KEY_SCAN | 40               ] = F_KVERB | K_DNARR;       /* Down Arrow  Numeric */

        rollstate[vmode] = tt_roll[vmode] ;
        scrollstate[vmode] = scrollflag[vmode] ;
        markmodeflag[vmode] = inmarkmode ;

        if (!scrollstate[vmode]) {
            scrollstatus[vmode] = TRUE ;
            }

        scrollstatusline() ;
        scrollflag[vmode] = TRUE ;
        if ( !scrollstate[vmode] )
            VscrnSetScrollTop( vmode, VscrnGetTop(vmode, FALSE, TRUE) ) ;
        VscrnIsDirty(vmode) ;
        return ;
        }  /* if (markmode[vmode] == notmarking) */

        switch (k &= ~(F_KVERB)) {
        case K_MARK_START:
            scrollstatusline();
            markstart(vmode) ;
            break;

        case K_MARK_CANCEL:
            markcancel(vmode) ;
            break;

        case K_MARK_COPYCLIP:
            markcopyclip(vmode,0) ;
            break;

        case K_MARK_COPYHOST:
            markcopyhost(vmode,0) ;
            break;

       case K_MARK_SELECT:
            markselect(vmode,0);
            break;

        case K_MARK_COPYCLIP_NOEOL:
            markcopyclip(vmode,1) ;
            break;

        case K_MARK_COPYHOST_NOEOL:
            markcopyhost(vmode,1) ;
            break;

       case K_MARK_SELECT_NOEOL:
            markselect(vmode,1);
            break;

        case K_DNONE:
        case K_DNARR:
            markdownone(vmode) ;
            break;

        case K_UPONE:
        case K_UPARR:
            markupone(vmode) ;
            break;

        case K_LFONE:
        case K_LFARR:
            markleftone(vmode) ;
            break;

        case K_RTONE:
        case K_RTARR:
            markrightone(vmode) ;
            break;

        case K_DNSCN:
            markdownscreen(vmode) ;
            break;

        case K_UPSCN:
            markupscreen(vmode) ;
            break;

        case K_DNHSCN:
            markdownhalfscreen(vmode) ;
            break;

        case K_UPHSCN:
            markuphalfscreen(vmode) ;
            break;

        case K_HOMSCN:
            markhomescreen(vmode) ;
            break;

        case K_ENDSCN:
            markendscreen(vmode) ;
            break;

#ifdef IN_PROGRESS  /* They just are not finished */
        case K_LFPAGE:
            markleftpage(vmode) ;
            break;

        case K_RTPAGE:
            markrightpage(vmode) ;
            break;
#endif /* IN_PROGRESS */

        case K_DUMP:
            markprint(vmode, 0);
            break;

        case K_HELP:                    /* Help */
            while ( popuphelp( vmode, hlp_markmode ) == ( F_KVERB | K_HELP ) ) ;
            return;

        case K_EXIT:            /* Exit terminal mode */
            markcancel(vmode);
            putkey( vmode, vik.exit ) ;
            return ;

    case K_QUIT:            /* Quit Kermit */
            markcancel(vmode);
            putkey( vmode, vik.quit ) ;
            return ;

    case K_BACKSRCH:
           if (!search( vmode, FALSE, TRUE ) )
           {
              markcancel(vmode);
              bleep(BP_FAIL);
           }
           break;

    case K_BACKNEXT:
           if (!search( vmode, FALSE, FALSE ))
           {
              markcancel(vmode);
              bleep(BP_FAIL);
           }
           break;
    case K_FWDSRCH:
           if (!search( vmode, TRUE, TRUE ))
           {
              markcancel(vmode);
              bleep(BP_FAIL);
           }
           break;
    case K_FWDNEXT:
           if (!search( vmode, TRUE, FALSE ))
           {
              markcancel(vmode);
              bleep(BP_FAIL);
           }
           break;

        default:
            bleep(BP_WARN);
        }

    if ( markmodeflag[vmode] == notmarking ) {
        if (scrollstate[vmode]) {
            scrollstatusline() ;
            }
        else {
            scrollstatus[vmode] = FALSE ;
            ipadl25() ;   /* put back the normal status line */
            }

        scrollflag[vmode] = scrollstate[vmode] ;
        tt_roll[vmode] = rollstate[vmode] ;

        VscrnSetCurPosEx( vmode, wherex[vmode] -1, wherey[vmode]-1, FALSE ) ;

        /* Restore Macro and KeyMap settings for Arrow keys */

        macrotab[KEY_SCAN | KEY_ENHANCED | 38] = savemacros[0] ;     /* Up Arrow    Gray */
        macrotab[KEY_SCAN | 38               ] = savemacros[1] ;     /* Up Arrow    Numeric */
        macrotab[KEY_SCAN | KEY_ENHANCED | 37] = savemacros[2] ;     /* Left Arrow  Gray */
        macrotab[KEY_SCAN | 37               ] = savemacros[3] ;     /* Left Arrow  Numeric*/
        macrotab[KEY_SCAN | KEY_ENHANCED | 39] = savemacros[4] ;     /* Right Arrow Gray */
        macrotab[KEY_SCAN | 39               ] = savemacros[5] ;     /* Right Arrow Numeric */
        macrotab[KEY_SCAN | KEY_ENHANCED | 40] = savemacros[6] ;     /* Down Arrow  Gray */
        macrotab[KEY_SCAN | 40               ] = savemacros[7] ;     /* Down Arrow  Numeric */

        keymap[KEY_SCAN | KEY_ENHANCED | 38] = savekeys[0] ;         /* Up Arrow    Gray */
        keymap[KEY_SCAN | 38               ] = savekeys[1] ;         /* Up Arrow    Numeric */
        keymap[KEY_SCAN | KEY_ENHANCED | 37] = savekeys[2] ;         /* Left Arrow  Gray */
        keymap[KEY_SCAN | 37               ] = savekeys[3] ;         /* Left Arrow  Numeric*/
        keymap[KEY_SCAN | KEY_ENHANCED | 39] = savekeys[4] ;         /* Right Arrow Gray */
        keymap[KEY_SCAN | 39               ] = savekeys[5] ;         /* Right Arrow Numeric */
        keymap[KEY_SCAN | KEY_ENHANCED | 40] = savekeys[6] ;         /* Down Arrow  Gray */
        keymap[KEY_SCAN | 40               ] = savekeys[7] ;         /* Down Arrow  Numeric */
        } /* if ( markmodeflag[vmode] == notmarking ) */

    os2settitle(NULL,1);
    VscrnIsDirty(vmode);
#endif /* NOKVERBS */
}

/* Scrollback handler */
/*
  Totally rewritten for edit 190 to allow TERMINAL ROLL options and to
  use new keymap  - fdc.

  And again for 191 - jaltman.
*/

void
scrollback(BYTE vmode, int k) {                 /* Keycode */
#ifndef NOKVERBS

    /* Initialization */

#ifdef DEBUG
    debug(F101,"scrollback key","",key);
    debug(F101,"scrollback tt_roll","",tt_roll[vmode]);
#endif /* DEBUG */

    if ( !tt_scroll || (vmode == VTERM && !tt_term_scroll)) {
        debug(F100,"scrollback disabled","",0);
        return;
    }
/*
  If TERMINAL ROLL OFF, we just process the argument key and return control of
  the keyboard to the user.  This lets the user type characters to the host
  while looking at rollback screens, as well as view new incoming characters
  on an old screen.  But it can result in some confusion by mixing new and old
  material in the rollback buffer.

  If TERMINAL ROLL ON, the user is held captive inside the rolled-back
  screens, allowed to type only rollback keys until reaching the bottom again,
  and no characters are read from the communication device while rolled back.
  This prevents transmission of characters to the host, and it prevents
  mixture of new and old material in the rollback buffer.

  This is not true in this code anymore.  We always fall through regardless
  of ROLL ON or OFF.
*/
    switch (k &= ~(F_KVERB)) {  /* Handle the key... */

    case K_GO_BOOK:       /* Scroll to Bookmark location */
       bookmarkjump(vmode);
       break;

    case K_GOTO:
       gotojump(vmode);
       break;

    case K_HOMSCN:              /* Scrolling UP (backwards) ... */
        if (!tt_roll[vmode]) {
            if ( VscrnSetTop(vmode, VscrnGetBegin(vmode, FALSE, TRUE), FALSE, TRUE) < 0 )
              bleep(BP_WARN) ;
        }
        else {
            if ( VscrnSetScrollTop(vmode,VscrnGetBegin(vmode, FALSE, TRUE)) < 0 )
              bleep(BP_WARN);
        }
        break;

    case K_UPSCN:
        if (!tt_roll[vmode]) {
            if ( VscrnMoveTop(vmode,-(VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))) < 0 )
              if ( VscrnSetTop(vmode,VscrnGetBegin(vmode, FALSE, TRUE),FALSE, TRUE) < 0 )
                bleep(BP_WARN) ;
        }
        else {
            if ( VscrnMoveScrollTop(vmode,-(VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))) < 0 )
              if ( VscrnSetScrollTop(vmode,VscrnGetBegin(vmode, FALSE, TRUE)) < 0 )
                bleep(BP_WARN);
        }
        break;

    case K_UPHSCN:
        if (!tt_roll[vmode]) {
            if ( VscrnMoveTop(vmode,-((VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))/2)) < 0 )
                if ( VscrnSetTop(vmode,VscrnGetBegin(vmode, FALSE, TRUE), FALSE, TRUE) < 0 )
                    bleep(BP_WARN) ;
        }
        else {
            if ( VscrnMoveScrollTop(vmode,-((VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))/2)) < 0 )
                if ( VscrnSetScrollTop(vmode,VscrnGetBegin(vmode, FALSE, TRUE)) < 0 )
                    bleep(BP_WARN);
        }
        break;

    case K_UPONE:
        if (!tt_roll[vmode]) {
            if ( VscrnMoveTop(vmode,-1) < 0 )
              bleep(BP_WARN) ;
        }
        else {
            if ( VscrnMoveScrollTop(vmode,-1) < 0 )
              bleep(BP_WARN);
        }
        break;

    case K_DNSCN:                       /* Go down */
        if (!tt_roll[vmode]) {
            if ( VscrnMoveTop(vmode,VscrnGetHeight(vmode)-(tt_status[vmode]?1:0)) < 0 )
              if ( VscrnSetTop(vmode,VscrnGetEnd(vmode,FALSE,TRUE) - VscrnGetHeight(vmode)+1, FALSE, TRUE) < 0 )
                bleep(BP_WARN);
        }
        else {
            if ( VscrnMoveScrollTop(vmode,VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0)) < 0 )
              if ( VscrnSetScrollTop(vmode,VscrnGetEnd(vmode,FALSE,TRUE)
                                      - (VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))+1) < 0 )
                bleep(BP_WARN);
        }
        break;

    case K_DNHSCN:                       /* Go down half a screen */
        if (!tt_roll[vmode]) {
            if ( VscrnMoveTop(vmode,(VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))/2) < 0 ) {
                if ( VscrnSetTop(vmode,VscrnGetEnd(vmode,FALSE,TRUE) - VscrnGetHeightEx(vmode,FALSE)+1,FALSE,TRUE) < 0 ) {
                    bleep(BP_WARN);
                }
            }
        }
        else {
            if ( VscrnMoveScrollTop(vmode,(VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))/2) < 0 ) {
                if ( VscrnSetScrollTop(vmode,VscrnGetEnd(vmode,FALSE,TRUE)
                                        - (VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0))+1) < 0 ) {
                    bleep(BP_WARN);
                }
            }
        }
        break;

    case K_DNONE:
        if (!tt_roll[vmode]) {
            if ( VscrnMoveTop(vmode,1) < 0 )
              bleep(BP_WARN);
        }
        else {
            if ( VscrnMoveScrollTop(vmode,1) < 0 )
              bleep(BP_WARN);
        }
        break;

    case K_ENDSCN:              /* Scroll to bottom */
        if (!tt_roll[vmode]) {
            if ( VscrnSetTop(vmode,
                VscrnGetEnd(vmode,FALSE,TRUE)
                - VscrnGetHeightEx(vmode,FALSE) - (tt_status[vmode]?1:0) + 1,
                FALSE,TRUE) < 0 ) {
              bleep(BP_WARN);
            }
        }
        else {
            if ( VscrnSetScrollTop(vmode,VscrnGetTop(vmode,FALSE,TRUE)) < 0 )
              bleep(BP_WARN);
        }
        break;

    case K_DUMP: {              /* Print/Dump current screen */
        int x;
        x = xprintff; xprintff = 0;
        prtscreen(vmode,1,VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?1:0));
        xprintff = x;
        break;
    }

    case K_HELP: {              /* Help */
        int x = hlp_rollback;
        while ( popuphelp(vmode,x) == ( F_KVERB | K_HELP ) )
            switch ( x ) {
#ifdef OS2MOUSE
            case hlp_rollback:
                x = hlp_mouse;
                break;
            case hlp_mouse:
                x = hlp_rollback;
                break;
#else /* OS2MOUSE */
            case hlp_rollback:
                x = hlp_rollback;
                break;
#endif /* OS2MOUSE */
            }
        killcursor(vmode);              /* Turn it back off */
        break;
    }

    case K_MARK_START:
        markmode(vmode,K_MARK_START);
        break;

    case K_EXIT:
        putkey( vmode, vik.endscn ) ;
        putkey( vmode, vik.exit ) ;
        break ;

    case K_QUIT:
        putkey( vmode, vik.endscn ) ;
        putkey( vmode, vik.quit ) ;
        break ;

    default:                    /* Not a rollback key. */
        bleep(BP_WARN);
        break;

    } /* switch (k) */

    scrollflag[vmode] = tt_roll[vmode] && ( VscrnGetTop(vmode,FALSE,TRUE) != VscrnGetScrollTop(vmode,FALSE) ) ;

    if ( !scrollstatus[vmode] ) {
        scrollstatus[vmode] = TRUE ;
        scrollstatusline() ;
    }

/*
  Get here after processing one keystroke and TERMINAL ROLL is OFF,
  or when TERMINAL ROLL is ON, only when we've reached the bottom.
  Wrong.
*/
    if ( !scrollflag[vmode] ) {
        if (tt_roll[vmode] ||
             (VscrnGetTop(vmode,FALSE,TRUE)+VscrnGetHeightEx(vmode,FALSE)-(tt_status[vmode]?2:1))
				% VscrnGetBufferSize(vmode, FALSE, TRUE) == VscrnGetEnd(vmode,FALSE,TRUE))
        {
            scrollstatus[vmode] = FALSE ;
            ipadl25();                  /* Put back normal status line */
        }
    } /* if ( !scrollflag[vmode] ) */

    os2settitle(NULL,1);
    VscrnIsDirty(vmode) ;
#endif /* NOKVERBS */
}

void
vt100key(int key) {
#ifdef NOKVERBS
    char str[3];                        /* Not needed in simplified code */
    int prt, st;
#endif /* NOKVERBS */

    if ( keydefptr ) {                  /* First send any leftovers */
        sendkeydef( keydefptr,FALSE );  /* from previous session... */
        keydefptr = NULL;                   /* and then forget about it */
        return;
    }

    if (key < 0x100 && !kbdlocked()) {      /* If it's a regular key, */
        sendcharduplex((char) key,FALSE);/* just send it, */
        if (tt_pacing > 0)              /* taking care of pacing */
            msleep(tt_pacing);
        if (key == CK_CR && tnlm) {        /* and newline mode */
            if (tt_pacing > 0)          /* and pacing */
                msleep(tt_pacing);
        }
        return;
    }

    /* vt100key is only called from within conkbdhandler() */
    /* and all events are handled there, so how would this */
    /* get here */
    if ( IS_CSI(key) ) {
        char buf[3] ;
        buf[0] = '[' ;
        buf[1] = key & 0xFF ;
        buf[2] = NUL ;
        sendescseq(buf) ;
    }
    else if ( IS_ESC(key) ) {
        char buf[2] ;
        buf[0] = key & 0xFF ;
        buf[1] = NUL ;
        sendescseq(buf) ;
    }
#ifndef NOKVERBS
    else if (IS_KVERB(key)) {        /* Specially precoded keyboard verb */
        dokverb(VTERM,key) ;          /* We already know its index */
    }
    else
        bleep(BP_WARN);                         /* Extended key with no definition. */
    return;                             /* Just beep & return. */
#endif /* NOKVERBS */
}

#ifdef CK_APC

/* Parse color specification compatible with XParseColor. Only the following
 * formats are currently supported:
 * 	 rgb:r/g/b
 *   rgb:rr/gg/bb
 *   rgb:rrr/ggg/bbb
 *   rgb:rrrr/gggg/bbbb
 *   #rgb
 *   #rrggbb
 *   #rrrgggbbb
 *   #rrrrggggbbbb
 *
 * If the color specification is invalid, COLORSPEC_INVALID is returned.
 * If the color specification starts with "?", COLORSPEC_QUERY is returned.
 *
 * XParseColor formats not supported:
 *    rgbi:
 *	  CIEXYZ:
 *    CIEuvY:
 *    CIExyY:
 *    CIELab:
 *    CIELuv:
 *    TekHVC:
 */
#define COLORSPEC_MAX 25
#define COLORSPEC_INVALID -1
#define COLORSPEC_QUERY -2
int colorspec(int *achar, int* apcnext) {
    int color = 0, i=0;
    unsigned int r, g, b;
    char spec[COLORSPEC_MAX];

    while (*achar != ';' && *achar != 0) {
        debug(0, "Colorspec", "achar", *achar);
        if (i == COLORSPEC_MAX - 1) {
            spec[i] = 0;
            debug(F110, "Colorspec buffer limit!", spec, 0);
			return COLORSPEC_INVALID;
        }
        spec[i] = *achar;
		i++;
        *achar = ((*apcnext)<=apclength)?apcbuf[(*apcnext)++]:0;
    }
    spec[i] = 0;

    debug(F110, "Colorspec", spec, 0);

    if (spec[0] == '?') {
        debug(F110, "Colorspec is a query", spec, 0);
        return COLORSPEC_QUERY;
    }

    if (i < 4) {
        debug(F101, "Colorspec length too short", 0, i);
        return COLORSPEC_INVALID;
    }

    /* Try to parse the color spec */
    if (ckstrcmp("rgb:", spec, 4, 0) == 0) {
        /* rgb:r/g/b format */
		switch(i) {
            case 9:		/* rgb:R/G/B */
				if (sscanf(spec, "rgb:%1x/%1x/%1x", &r, &g, &b) != 3) {
					debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;
				}
				r *= 17;
				g *= 17;
                b *= 17;
				break;
            case 12:	/* rgb:RR/GG/BB */
                if (sscanf(spec, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) {
					debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;
				}
				break;
            case 15:	/* rgb:RRR/GGG/BBB */
                if (sscanf(spec, "rgb:%3x/%3x/%3x", &r, &g, &b) != 3) {
					debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;return FALSE;
				}
				r >>= 4;
                g >>= 4;
            	b >>= 4;
				break;
			case 18:	/* rgb:RRRR/GGGG/BBBB */
                if (sscanf(spec, "rgb:%4x/%4x/%4x", &r, &g, &b) != 3) {
					debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;
				}
				r >>= 8;
                g >>= 8;
                b >>= 8;
				break;
			default:
                debug(F110, "Colorspec length invalid", spec, i);
				return COLORSPEC_INVALID;
        }
    } else if (spec[0] == '#') {
      	/* #rgb format */
		switch (i) {
		    case 4:		/* #RGB */
			    if (sscanf(spec, "#%1x%1x%1x", &r, &g, &b) != 3) {
				    debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;
			    }
			    r <<= 4;
                g <<= 4;
                b <<= 4;
			    break;
		  	case 7:		/* #RRGGBB */
				if (sscanf(spec, "#%2x%2x%2x", &r, &g, &b) != 3) {
					debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;
				}
				break;
		  	case 10:	/* #RRRGGGBBB */
				if (sscanf(spec, "#%3x%3x%3x", &r, &g, &b) != 3) {
					debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;
				}
				r >>= 4;
                g >>= 4;
                b >>= 4;
				break;
		  	case 13:	/* #RRRRGGGGBBBB */
				if (sscanf(spec, "#%4x%4x%4x", &r, &g, &b) != 3) {
					debug(F110, "Colorspec format invalid", spec, i);
					return COLORSPEC_INVALID;
				}
				r >>= 8;
                g >>= 8;
                b >>= 8;
				break;
		  default:
                debug(F110, "Colorspec length invalid", spec, i);
				return COLORSPEC_INVALID;
		}
    } else {
        /* Try to look it up as an x11 color name */
        int i = 0;
        int found = FALSE;
        while (x11colors[i].name != 0) {
            if (_stricmp(x11colors[i].name, spec) == 0) {
                found = TRUE;
                r = x11colors[i].red;
                g = x11colors[i].green;
                b = x11colors[i].blue;
                break;
            }
            i++;
        }

        if (!found) {
            debug(F110, "Colorspec format or name unsupported", spec, 0);
            return COLORSPEC_INVALID;
        }
    }

    if (r > 255 | g > 255 | b > 255) {
      	debug(F110, "Colorspec component out of range (max 255)", spec, 0);
        debug(F111, "Colorspec component out of range", "r", r);
        debug(F111, "Colorspec component out of range", "g", g);
        debug(F111, "Colorspec component out of range", "b", b);
        return COLORSPEC_INVALID;
    }

    debug(F111, "Colorspec component", "r", r);
    debug(F111, "Colorspec component", "g", g);
    debug(F111, "Colorspec component", "b", b);

    color = (unsigned)(((unsigned)b << 16) |
        (unsigned)((unsigned)g << 8) |
        (unsigned)r);

    debug(F111, "Colorspec", "color", color);
    return color;
}

/* ------------------------------------------------------------------ */
/* doosc - process OSC sequences (VT320 and higher)                   */
/*         sequence of apclength in apcbuf                            */
/* ------------------------------------------------------------------ */

/* This buffer was originally 31 characters for some reason. This is
 * pretty short and the os2settitle functions buffer is 128 so titles
 * of up to 64 chars seems more reasonable.
 */
#define APC_TITLE_BUF_LEN 64

void
doosc( void ) {
	int num = 0;
	int apcnext = 0;

    debug(F111, "OSC string", apcbuf, apclength);

    if ( debses )              /* If TERMINAL DEBUG ON */
      return ;                 /* don't do anything    */

    /* The contents of apcbuf *should* be of the form:
     *    <OSC> number ; string <ST>
     * But for compatibility with aixterm and xterm, we also accept:
     *    <OSC> number ; string <BEL>
     * When the string is terminated with <BEL>, the oscterm variable will be
	 * set to 7 (BEL).
     *
     * Additionally, there are a few exceptions to the above rules supposedly
     * from dtterm:
     *    <OSC> I string <ST/BEL>
	 *    <OSC> l string <ST/BEL>
	 *    <OSC> L string <ST/BEL>
     * And one from the VT5xx series:
     *    <OSC> 2 L ; string <ST/BEL>
     */

    achar = (apcnext<apclength)?apcbuf[apcnext++]:0;

    /* Check the first character to deal with OSC sequences that start with a
     * letter rather than a number. If the first character is a digit instead,
	 * then read in the number to deal wioth the normal
     * <OSC> number ; string <ST/BEL> form.*/
    switch (achar) {
      case 'I': /* dtterm - set icon to file */
        /* We can't really do this sensibly as the string will almost certainly
         * refer to some file on the remote host and we don't really have a
         * reliable way of getting at that from here. */
        debug(F111, "OSC I: dtterm - set icon file", apcbuf, apclength);
		return;
      case 'l': /* dtterm - set window title */
		num = 0;  /* fall through to number */
        achar = (apcnext<apclength)?apcbuf[apcnext++]:0;
        debug(F111, "OSC l: dtterm - set window title", apcbuf, apclength);
        if (achar != ';') {
          debug(F111, "Expected 'OSC l ; <string>' sequence, got 'OSC l <string>'", apcbuf, apclength);
          return;
        }
        break;
      case 'L': /* dtterm - set icon label */
        /* On Windows, the nearest equivalent would be setting the task bar
         * label, something Windows doesn't let you do. The taskbar label will
         * always be the window title.
         */
        debug(F111, "OSC L: dtterm - set icon label", apcbuf, apclength);
        return;
      default:  /* Look for a number */
		if (!isdigit(achar)) {
			debug(F111, "OSC string first character unrecongised", apcbuf, apclength);
			return;
		}
        while (isdigit(achar)) {
        	num = (num * 10) + achar - 48;
            achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;
    	}
    }

    debug(F111, "OSC", "num", num);

    if (num == 2 && achar == 'L') {
        /* <OSC> 2 L ; name <ST>
	     * DECSIN - Set Icon Name.
         * Not currently supported as Win32 doesn't provide a way of setting the
         * task bar button label to something other than the window title */
        debug(F100, "DECSIN - Set Icon Title", 0, 0);
        return;
    } else if (achar != ';' && apcnext <= apclength) {
        /* If there is more following the number, it should be separated from the
         * number by a semicolon. If there is *only* the number (eg, OSC 104 ST)
         * then don't require the semicolon. */
        debug(F111, "Invalid OSC - expected ';' following number", apcbuf, apclength);
        debug(F101, "Invalid OSC - achar", 0, achar);
        return;
    }

    /* AIXTERM */
    /*   0 - Set Icon and Title */
    /*   1 - Set Icon only      */
    /*   2 - Set Title only     */

    switch ( num ) {
    case 0:  /* dtterm, xterm - set icon name and window title */
    case 2:  /* dtterm, xterm - Set Window Title */
	case 21: /* VT520 - DECSWT - Set Window Title */
    {
        /* the rest of the apcbuffer is the Window Title */
        char wtitle[APC_TITLE_BUF_LEN] ;
        int i, j = 0 ;

        /* Take 1 off to leave room for the NUL at the end */
        for ( i=apcnext; i < APC_TITLE_BUF_LEN - 1 && i < apclength; i++ ) {
            wtitle[j] = apcbuf[i] ;
            j++;
        }

        if ( i > 0 && apcbuf[i-1] == 0x07 ) {
            /* XTERMs may append a Beep indicator at the end */
            wtitle[j-1] = NUL ;
            bleep(BP_NOTE);
        }
        else {
            wtitle[j] = NUL ;
		}

        debug(F110, "OSC 0/2/21: set window title", wtitle, 0);

        if (!os2settitle(wtitle,1)) {
            bleep(BP_FAIL);
            debug(F110,"doosc os2settitle fails",wtitle,0);
        }
        break;
    }
    case 1: /* dtterm, xterm - set Icon Name */
        debug(F111, "OSC 1: set icon name", apcbuf, apclength);
		/* Not currently supported as Win32 doesn't provide a way of setting the
         * task bar button label to something other than the window title.
		 * Chances are effectively nothing happens here with xterm too for
		 * similar reasons - most modern window manages probably don't support
		 * it either.
		 *
		 * Tera Term overwrites the window title with this value.
		 * iTerm2 uses this to set the tab name rather than window title
		 */
        break;

#ifdef KUI
	case 5:   /* xterm : Change Special Color Number*/
    case 4: { /* xterm : Change color number */
        /* Text is: c ; spec ; c ; spec ; c ; spec ; ...
         * Where c is:
		 *   - An index into the current palette (case 4)
         *   - One of the special color numbers added to the size of the
         *     current palette (case 4)
         *   - One of the special color numbers (case 5)
         * And spec is the name of a color specification as per XParseColor.
         * Any number of c;spec pairs can be supplied. If spec is a "?", then
         * K95 responds with the escape sequence for setting that color pair.
		 *
         * Special Color Numbers (case 5):
         *    0   - Bold color (boldattribute)
         *    1   - Underline color (underlineattribute)
         *    2   - Blink color (blinkattribute_
         *    3   - Reverse color (reverseattribute)
         *    4   - Italic color (italicattribute)
         *
		 * Special Color Numbers (case 4, example for the 256-color palette):
         *    256   - Bold color (boldattribute))
         *    257   - Underline color (underlineattribute)
         *    258   - Blink color (blinkattribute)
         *    259   - Reverse color (reverseattribute)
         *    260   - Italic color (italicattribute)
 	     */

        ULONG *palette = NULL;
        int palette_max = 15;
        int idx = 0, pal_idx = 0;
        char buf[256];

        debug(F111, "OSC 4/5: Change color number", apcbuf, apclength);

        palette_max = current_palette_max_index();
        palette = current_palette_rgb_table();

		debug(F101, "OSC 4/5 palette_max", 0, palette_max);

        if (num == 5) {  /* Change Special Color Number */
			palette_max = 0;
        }

        /* Format of string is:
    		c;spec;c;spec;c;spec...
         */
        do {
			int idx = 0, color = 0;

            /* Ready the next character! */
    		achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;

            if (!isdigit(achar)) {
				debug(F111, "OSC 4/5: Expected digit", "apcnext", apcnext);
            	debug(0, "OSC 4/5: Expected digit", "achar", achar);
				break;
        	}

            /* Get c */
			while (isdigit(achar)) {
        		idx = (idx * 10) + achar - 48;
            	achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;
    		}

            debug(F111, "OSC 4/5: start pair", "idx", idx);

            /* A few colors in the 0-15 range are swapped around in the K95
             * palette for historic OS/2 reasons, so transalte the normal index
             * to one that accounts for this. */
            pal_idx = color_index_to_vio(idx);

            if (achar != ';') {
                debug(0, "OSC 4/5: Expected ';' following color index, got", "achar", achar);
            }
            achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;

			/* Get spec */
			color = colorspec(&achar, &apcnext);

			if (color == COLORSPEC_INVALID) continue;  /* Invalid colorspec */

			if (color == COLORSPEC_QUERY) {  /* c;? */
                /* Query */
                debug(F100, "OSC 4/5: got query", 0, 0);

				if (idx > palette_max || num == 5) {
					int r, g, b, ok = TRUE;
					cell_video_attr_t attr;

					if (num != 5) idx -= palette_max + 1;
                	switch(idx) {
						/* These all set the foreground only. */
                    	case 0: /* Bold attribute */
							attr = boldattribute;
							break;
                   		case 1: /* underline attribute */
							attr = underlineattribute;
							break;
                		case 2: /* blink attribute */
							attr = blinkattribute;
							break;
    	                case 3: /* Reverse attribute */
							attr = reverseattribute;
							break;
						case 4: /* Italic attribute */
							attr = italicattribute;
							break;
					    default:
							debug(F101, "OSC 4/5: Unknown or Unsupported Special Color Number", 0, idx);
							ok = FALSE;
					}

					if (ok) {
						int color = cell_video_attr_foreground_rgb(attr);
						r =  color & 0x000000FF;
                		g = (color & 0x0000FF00)>>8;
                		b = (color & 0x00FF0000)>>16;
						_snprintf(buf, sizeof(buf),
	                          		oscterm == BEL ? "\033]%d;%d;rgb:%04x/%04x/%04x\07"
                            	      	           : "\033]%d;%d;rgb:%04x/%04x/%04x\033\\",
                       	      		num, idx,r * 257,g * 257,b * 257);
						buf[255] = 0;
						sendchars(buf, strlen(buf));
					}
				} else if (idx >= 0) {
                	color = palette[pal_idx];
					_snprintf(buf, sizeof(buf),
                              oscterm == BEL ? "\033]%d;%d;rgb:%04x/%04x/%04x\07"
                                             : "\033]%d;%d;rgb:%04x/%04x/%04x\033\\",
                              num, idx,
							  (palette[idx] & 0x000000FF) * 257,  /* Red */
                              ((palette[idx] & 0x0000FF00)>>8) * 257, /* Green */
                              ((palette[idx] & 0x00FF0000)>>16) * 257); /* Blue */
					buf[255] = 0;
					sendchars(buf, strlen(buf));
                } else {
                  	debug(F111, "OSC 4/5: query index out of range for current palette", "index", idx);
                }
            } else if (idx > palette_max || num == 5) {  /* OSC 4/5: Set attribute color */
				int r,g,b;

				if (num != 5) idx -= palette_max + 1;
                debug(F111, "OSC 4/5: Set special color", "idx", idx);
                debug(F111, "OSC 4/5: Set special color", "color", color);

				r =  color & 0x000000FF;
                g = (color & 0x0000FF00)>>8;
                b = (color & 0x00FF0000)>>16;

                switch(idx) {
					/* Aside from the reverse attribute, these all set the
					 * foreground only. */
                    case 0: /* Bold attribute */
						boldattribute = cell_video_attr_set_fg_rgb(boldattribute, r, g, b);
						break;
                    case 1: /* underline attribute */
						underlineattribute = cell_video_attr_set_fg_rgb(underlineattribute, r, g, b);
						break;
                	case 2: /* blink attribute */
						blinkattribute = cell_video_attr_set_fg_rgb(blinkattribute, r, g, b);
						break;
                    case 3: /* Reverse attribute */
						reverseattribute = cell_video_attr_set_bg_rgb(reverseattribute, r, g, b);
						break;
					case 4: /* Italic attribute */
						italicattribute = cell_video_attr_set_fg_rgb(italicattribute, r, g, b);
						break;
				    default:
						debug(F101, "OSC 4/5: Unknown or Unsupported Special Color Number", 0, idx);
                }
            } else { /* OSC 4: Set Palette Color */
              	debug(F111, "OSC 4: set palette color", "index", idx);
                debug(F111, "OSC 4: set palette color", "color", color);
                palette[pal_idx] = color;
            }
        } while (achar == ';');

        break;
    }
#endif /* KUI */

    case 6:
    case 106: { /* xterm : Enable/disable special color number */
		int idx = 0, f = 0;

    	achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;

        if (!isdigit(achar)) {
			debug(F111, "OSC 6/106: Expected digit", "apcnext", apcnext);
            debug(0, "OSC 6/106: Expected digit", "achar", achar);
			break;
        }

        /* Get c */
		while (isdigit(achar)) {
        	idx = (idx * 10) + achar - 48;
           	achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;
    	}

        if (achar != ';') {
			/* Xterm does nothing if no parameter is received after the special
			 * color number */
            debug(0, "OSC 6/106: Expected ';' following color index, got", "achar", achar);
			break;
        }
        achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;

        /* Get f */
		while (isdigit(achar)) {
        	f = (f * 10) + achar - 48;
           	achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;
    	}

		if (f < 0) {
			debug(F100, "OSC 6/106: Missing second parameter", 0, 0);
			break;
		}

		if (!f) debug(F111, "OSC 6/106: Enable true attribute", "idx", idx);
		else debug(F111, "OSC 6/106: Disable true attribute", "idx", idx);

		switch(idx) {
            case 0: /* Bold attribute */
				truebold = !f;
				use_bold_attr = f;
				break;
            case 1: /* underline attribute */
				trueunderline = !f;
				break;
            case 2: /* blink attribute */
				trueblink = !f;
				use_blink_attr = f;
				break;
            case 3: /* Reverse attribute */
				truereverse = !f;
				break;
			case 4: /* Italic attribute */
				trueitalic = !f;
				break;
			case 5: /* colorAttrMode */
                /* When this is turned on via .Xresources, it causes attribute
                 * colors to take priority over SGR colors (K95s default
                 * behaviour), while when off SGR colors take priority.
                 * When this is turned on or off via OSC-106, xterm(390) doesn't
                 * obviously change its behaviour - possibly a bug. */
                colorAttPriority = f;
			default:
				debug(F101, "OSC 6/106: Unknown or Unsupported Special Color Number", 0, idx);
        }

        break;
    }
    case 7: /* TODO - Misc - inform current working directory */
		break; /* https://github.com/davidrg/ckwin/issues/413 */
	case 8: /* TODO - misc - hyperlink */
		break; /* https://github.com/davidrg/ckwin/issues/123 */
    /* Set various special colors. Each one consumes one parameter, sets
     *  the associated color, then if there are further parameters remaining in
     *  the osc string it falls through to the next case */
	case 10: /* set defaultattribute foreground */
	case 11: /* set defaultattribute background */
	case 12: /* set set text cursor color */
	case 13: /* TODO: set pointer color foreground*/
	case 14: /* TODO: set pointer color background */
	case 15: /* TODO: set tektronix foreground */
	case 16: /* TODO: set tektronix background */
	case 17: /* set colorselect background */
	case 18: /* TODO: set set tektronix cursor color */
	case 19: { /* set colorselect foreground color */
		int current_color_id = num - 1;
		char buf[256];

		debug(F101, "OSC 10-19: Change dynamic color, starting from:", 0, num);

		/* Format of string is:
    		c;spec;spec;spec...
         */
        do {
			int color = 0;
			current_color_id++;

			if (current_color_id > 19) break; /* finished */

            achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;

			/* Get spec */
			color = colorspec(&achar, &apcnext);

			if (color == COLORSPEC_INVALID) continue;  /* Invalid colorspec */

			if (color == COLORSPEC_QUERY) {  /* ? */
                /* Query */
				int r, g, b, ok = TRUE;
				cell_video_attr_t attr;

				debug(F100, "OSC 10-19: got query", 0, 0);

                switch(current_color_id) {
                    case 10: /* defaultattribute foreground */
						color = cell_video_attr_foreground_rgb(defaultattribute);
						break;
                   	case 11: /* defaultattribute background */
						color = cell_video_attr_background_rgb(defaultattribute);
						break;
					case 12: /* colorcursor background */
						color = cell_video_attr_background_rgb(colorcursor);
						break;
					case 17: /* colorselect background */
						color = cell_video_attr_background_rgb(colorselect);
		 				break;
					case 19: /* colorselect foreground */
						color = cell_video_attr_foreground_rgb(colorselect);
						break;
					default:
						color = 0;
						debug(F101, "OSC 10-19: Unknown or Unsupported Dynamic Color Number", 0, current_color_id);
						ok = FALSE;
				}

				if (ok) {
					r =  color & 0x000000FF;
                	g = (color & 0x0000FF00)>>8;
                	b = (color & 0x00FF0000)>>16;
					_snprintf(buf, sizeof(buf),
	                          	oscterm == BEL ? "\033]%d;rgb:%04x/%04x/%04x\07"
                            	      	       : "\033]%d;rgb:%04x/%04x/%04x\033\\",
                       	      	current_color_id, r * 257,g * 257,b * 257);
					buf[255] = 0;
					sendchars(buf, strlen(buf));
				}
            } else {  /* OSC 10-19: Set attribute color */
				int r,g,b;

                debug(F111, "OSC 10-19: Set dynamic color", "current_color_id", current_color_id);
                debug(F111, "OSC 10-19: Set dynamic color", "color", color);

				r =  color & 0x000000FF;
                g = (color & 0x0000FF00)>>8;
                b = (color & 0x00FF0000)>>16;

                switch(current_color_id) {
                    case 10: /* defaultattribute foreground */
						defaultattribute = cell_video_attr_set_fg_rgb(defaultattribute, r, g, b);
						break;
                   	case 11: /* defaultattribute background */
						defaultattribute = cell_video_attr_set_bg_rgb(defaultattribute, r, g, b);
						break;
					case 12: /* colorcursor background */
						colorcursor = cell_video_attr_set_bg_rgb(colorcursor, r, g, b);
		 				break;
					case 17: /* colorselect background */
						colorselect = cell_video_attr_set_bg_rgb(colorselect, r, g, b);
		 				break;
					case 19: /* colorselect foreground */
						colorselect = cell_video_attr_set_fg_rgb(colorselect, r, g, b);
						break;
				    default:
						debug(F101, "OSC 10-19: Unknown or Unsupported Special Color Number", 0, current_color_id);
                }
            }
        } while (achar == ';');

        break;
		}
	case 22: /* xterm - Change pointer shape */
	case 46: /* xterm - change log file */
	case 50: /* xterm - set font */
	case 51: /* xterm - reserved for emacs shell */
	case 52: { /* xterm - manipulate selection data */
        /* Format is OSC 52 ; Pc ; Pd ST
           Where Pc is some combination of zero or more of:
                c, p, q, s, 0, 1, 2, 3, 4, 5, 6, 7
           This specifies which of xterms various buffers we're manipulating.
           Windows only has one (the clipboard), and its not worth emulating
           the rest unless someone can point at an application that uses them.
           So we just ignore this first parameter */

        /* Don't use any of the code here as a good example for how to properly
            do character set/unicode conversion in Kermit 95. I just copied
            how it *appears* to be done elsewhere - I don't know if any of this
            is truly correct -- DG */

#ifdef NT
        int use_unicode = (ck_isunicode() && !isWin95());
#endif /* NT */

        achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;
        while (strchr("cps01234567", achar)) {
            achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;
        }

        if (achar == ';') {
            /* Pd is either '?' to query the current clipboard contents, or
             * it contains base64 encoded data to set the clipboard to.
             */
            achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;

            if (achar == '?' && apcnext == apclength) {

                /* Its a query */
                if (tt_clipboard_read >= CLIPBOARD_ALLOW) {
                    char* clipboardData = 0;
                    int clipboardDataLen = 0;

#ifdef KUI
#ifdef CK_SHELL_NOTIFY
                    if (tt_clipboard_read == CLIPBOARD_ALLOW_NOTIFY) {
                        KuiShowNotification(
                            KUI_NOTIF_I_INFO,
                            "Clipboard Read",
                            "Clipboard read by remote host allowed");
                    }
#endif /* CK_SHELL_NOTIFY */
#endif /* KUI */

                    /* Get data from the clipboard. On Windows NT, this will
                     * be Unicode text and will need converting to the remote
                     * character set. On Windows 9x and OS/2, we just send the
                     * clipboard text as-is after base64-encoding*/
#ifdef NT
                    if (use_unicode) {
                        USHORT * pUClipbrdData = GetUnicodeClipboardContent();

                        /* Convert from UCS-2 to whatever the remote charset is */
                        if ( pUClipbrdData ) {
                            int i=0, j=0, len = 0, nbytes;
                            unsigned char * bytes;

                            len = wcslen(pUClipbrdData);
                            debug(F111,"Clipboard","pUClipbrdData length",len);

                            nbytes = utorxlat(pUClipbrdData[0], &bytes);
                            if ( nbytes > 0 )
                                clipboardDataLen = nbytes;
                            for ( i=1; i<len; i++ ) {
                                if ( pUClipbrdData[i-1] != CK_CR || pUClipbrdData[i] != LF ) {
                                    nbytes = utorxlat(pUClipbrdData[i], &bytes);
                                    if ( nbytes > 0 )
                                        clipboardDataLen += nbytes;
                                }
                            }

                            clipboardData = (unsigned char *) malloc(clipboardDataLen+1);
                            memset(clipboardData, 0, clipboardDataLen+1);

                            nbytes = utorxlat(pUClipbrdData[0], &bytes);
                            while ( nbytes-- > 0 )
                                clipboardData[j++] = *bytes++;
                            for ( i=1; i<len; i++ ) {
                                if ( pUClipbrdData[i-1] != CK_CR || pUClipbrdData[i] != LF ) {
                                    nbytes = utorxlat(pUClipbrdData[i], &bytes);
                                    while ( nbytes-- > 0 )
                                        clipboardData[j++] = *bytes++;
                                }
                            }

                            free( pUClipbrdData ) ;
                        }
                    } else {
#endif /* NT */
                        clipboardData = GetClipboardContent();
                        clipboardDataLen = strlen(clipboardData);
#ifdef NT
                    }
#endif /* NT */

                    if (clipboardData != NULL) {
                        /* Allocate memory for the maximum length the base64
                         * encoded data could be */
                        int rc;
                        int encodedLen = 1 + (int)(ceil(clipboardDataLen/3.0)*4);
                        char* encodedData = malloc(encodedLen);
                        memset(encodedData, 0, encodedLen);

                        /* Encode it... */
                        if ((rc = b8tob64(clipboardData, -1, encodedData, encodedLen)) >= 0) {
                            /* Send it in the form: OSC 52 ;; data ST */
                            sendchars("\033]52;;", 6);
                            sendchars(encodedData, rc);
                            sendchars("\033\\", 2);
                        } else {
                            debug(F111, "base64 encode of clipboard data failed", "rc", rc);
                        }

                        free(clipboardData);
                        free(encodedData);
                    }
                }
#ifdef KUI
#ifdef CK_SHELL_NOTIFY
                else if (tt_clipboard_read == CLIPBOARD_DENY_NOTIFY) {
                    KuiShowNotification(
                        KUI_NOTIF_I_WARN,
                        "Clipboard Read",
                        "Clipboard read by remote host denied. You can enable "
                        "clipboard access (or disable this "
                        "notification) with the SET TERM CLIPBOARD-ACCESS "
                        "command");
                }
#endif /* CK_SHELL_NOTIFY */
#endif /* KUI */
            } else {
                /* Its a clipboard write */
                if (tt_clipboard_write >= CLIPBOARD_ALLOW) {
                    /* +1 for null termination, +1 because apcnext is already
                     * pointing one character in */
                    int cliplen = (apclength - apcnext) + 2;
                    char* encoded = malloc(cliplen);
                    char* decoded = malloc(cliplen);
                    int rc;
					memset( encoded, 0, cliplen ) ;
				    memset( decoded, 0, cliplen ) ;

#ifdef KUI
#ifdef CK_SHELL_NOTIFY
                    if (tt_clipboard_write == CLIPBOARD_ALLOW_NOTIFY) {
                        KuiShowNotification(
                            KUI_NOTIF_I_INFO,
                            "Clipboard Write",
                            "Clipboard write by remote host allowed");
                    }
#endif /* CK_SHELL_NOTIFY */
#endif /* KUI */

                    strncpy(encoded, apcbuf+apcnext - 1, cliplen);

					/* Reset the base64 decoder */
					b64tob8(NULL, 0, NULL, 0);

                    /* Base64 decode the clipboard data and set it */
                    rc = b64tob8(encoded, cliplen, decoded, cliplen);

					/* Reset the base64 decoder some more */
					b64tob8(NULL, 0, NULL, 0);

                    if (rc > 0) {
                        /* Worst case: each UTF-8 character becomes one UCS-2
                         * character. */
                        USHORT* ucs2_string = malloc(sizeof(USHORT) * cliplen);
                        memset(ucs2_string, 0, sizeof(USHORT) * cliplen);

                        /* Ok, now we have a slight difficulty: the new data for
                         * the clipboard has bypassed all normal characterset
                         * translation/unicode conversion because it was hidden
                         * away in base64 form. So now we've got to do all that
                         * work here */

                        /* The code here all works with UCS-2 because,
                         * unfortunately, thats all Kermit 95 supports at
                         * present. At some point we need a utf8-to-utf16
                         * conversion function so we can support more than just
                         * the basic multilingual plane, but thats a big job. */

                        if (tt_utf8) {
                            /* We're in UTF-8 mode - everything else the host is
                             * sending us is assumed to be in UTF-8, so the new
                             * text for the clipboard probably is too. So we
                             * now need to convert it to UCS-2 to hand off to
                             * Windows. */

                            int utf8_idx, ucs2_idx = 0, rc;
                            USHORT *us = NULL;

                            for (utf8_idx = 0; decoded[utf8_idx] != '\0'; utf8_idx++) {
                                rc = utf8_to_ucs2(decoded[utf8_idx], &us);
                                if (rc == 0) {
                                    /* UTF-8 sequence decoded, we have a UCS-2
                                       character */
                                    ucs2_string[ucs2_idx] = *us;
                                    ucs2_idx++;
                                } else if (rc < 0) {
                                    /* Decoding failed. Output U+FFFD */
                                    ucs2_string[ucs2_idx] = 0xfffd;
                                    ucs2_idx++;
                                }
                                /* Else more UTF-8 bytes are needed to assemble
                                 * the UCS-2 character. Continue. */
                            }
                        } else {
                            int i;
                            /* Remote is some 7-bit or 8-bit character set.
                             * Windows wants UCS-2, so we need to convert it. */

                            for (i = 0; decoded[i] != '\0'; i++) {
                                if (decoded[i] >= 128)
                                    ucs2_string[i] = (*xl_u[tcsr])(decoded[i]);
                                else
                                    ucs2_string[i] = decoded[i];
                                    /* Some other code passes it through TX_IBMC0GRPH
                                        if its not a control character we act on */
                            }
                        }

#ifdef NT
                        if (use_unicode) {
                            rc = CopyToClipboard((BYTE*)ucs2_string,
                                                 sizeof(USHORT) * cliplen);
                        } else
#endif /* NT */
                        {
                            /* We've now got the clipboard data as a UCS-2
                             * string, but we're on Windows 9x or OS/2 (or NT
                             * with Unicode support turned off), so we need to
                             * now convert it back from UCS-2 to whatever the
                             * local character set is */
                            int i;

                            memset(decoded, 0, cliplen);
                            for (i = 0; ucs2_string[i] != '\0'; i++) {
                                decoded[i] = ucs2_string[i] >= 128 ?
                                    (*xl_tx[tcsl])(ucs2_string[i]) : ucs2_string[i];
                            }

                            rc = CopyToClipboard(decoded, cliplen);
                        }
                    } else {
                        CopyToClipboard("", 1);
                    }

                    free(encoded);
                    free(decoded);
                }
#ifdef KUI
#ifdef CK_SHELL_NOTIFY
                else if (tt_clipboard_write == CLIPBOARD_DENY_NOTIFY) {
                    KuiShowNotification(
                            KUI_NOTIF_I_WARN,
                            "Clipboard Write",
                            "Clipboard write by remote host denied. You can "
                            "enable clipboard access (or disable this "
                            "notification) with the SET TERM CLIPBOARD-ACCESS "
                            "command");
                }
#endif /* CK_SHELL_NOTIFY */
#endif /* KUI */
            }
        }
        break;
    }
	case 60: /* XTQALLOWED - query allowed features */
	case 61: /* XTQDISALLOWED - query disallowed features */
        break;

#ifdef KUI
	case 105:   /* xterm - reset special color number */
	case 104: { /* xterm - reset color number */
		/* 104 ; c ; c ; c ; ...   - reset specified color numbers*/
		/* 104     - reset all color numbers */

        ULONG *palette = NULL, *saved = NULL;
        int palette_max = current_palette_max_index();
        palette = current_palette_rgb_table();
        saved = current_palette_saved_rgb_table();

        debug(F111, "OSC 104/105: Reset color number", apcbuf, apclength);

        /* No parameters! Reset everything! */
        if (apcnext > apclength || apcnext+1 > apclength) {
			if (num == 104) {
				/* reset color palette */
				int i;
                debug(F100, "OSC 104: Resetting color palette", 0, 0);
                for (i = 0; i <= palette_max; i++) palette[i] = saved[i];
			} else {
                debug(F100, "OSC 105: Resetting special colors", 0, 0);
				if (decscnm) boldattribute = byteswapcolors(colorbold);
				else boldattribute  = colorbold;

				if (decscnm) underlineattribute = byteswapcolors(colorunderline);
				else underlineattribute  = colorunderline;

				if (decscnm) blinkattribute = byteswapcolors(colorblink);
				else blinkattribute  = colorblink;

				if (decscnm) reverseattribute = byteswapcolors(colorreverse);
				else reverseattribute  = colorreverse;

				if (decscnm) italicattribute = byteswapcolors(coloritalic);
				else italicattribute  = coloritalic;
			}
        }

        if (num == 105) {  /* Reset Special Color Number */
			palette_max = 0;
        }

        /* format of string is:
			c;c;c;c;c;c...
         */
        do {
            int idx = 0, pal_idx = 0;
            achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;

            /* Get c */
			while (isdigit(achar)) {
        		idx = (idx * 10) + achar - 48;
            	achar = (apcnext<=apclength)?apcbuf[apcnext++]:0;
    		}

            debug(F111, "OSC 104/105: ", "idx", idx);

            /* A few colors in the 0-15 range are swapped around in the K95
             * palette for historic OS/2 reasons, so transalte the normal index
             * to one that accounts for this. */
            pal_idx = color_index_to_vio(idx);

            if (idx > palette_max || num == 105) {
                if (num == 105) idx -= palette_max + 1;
                debug(F111, "OSC 104/105: Reset special color", "idx", idx);

                /* This is only available in builds with 24-bit RGB support. In
				 * 16/256 color builds, the color attribute isn't capable of
				 * storing RGB values.
                 */

                switch(idx) {
                    case 0: /* Bold attribute */
						if (decscnm) boldattribute = byteswapcolors(colorbold);
						else boldattribute  = colorbold;
						break;
                    case 1: /* underline attribute */
						if (decscnm) underlineattribute = byteswapcolors(colorunderline);
						else underlineattribute  = colorunderline;
						break;
                	case 2: /* blink attribute */
						if (decscnm) blinkattribute = byteswapcolors(colorblink);
						else blinkattribute  = colorblink;
						break;
                    case 3: /* Reverse attribute */
						if (decscnm) reverseattribute = byteswapcolors(colorreverse);
						else reverseattribute  = colorreverse;
						break;
					case 4: /* Italic attribute */
						if (decscnm) italicattribute = byteswapcolors(coloritalic);
						else italicattribute  = coloritalic;
						break;
				    default:
						debug(F101, "OSC 104/105: Unknown or Unsupported Special Color Number", 0, idx);
                }
            } else {
                debug(F111, "OSC 104/105: Resetting color", "idx", idx);
                palette[pal_idx] = saved[pal_idx];
            }

        } while (achar == ';');

        break;
    }
#endif /* KUI */

	case 110: /* xterm - reset attribute foreground */
		if ( decscnm ) {  /* Reverse screen? Set FG to colornormal BG*/
#ifdef CK_COLORS_24BIT
			if (!cell_video_attr_bg_is_indexed(colornormal)) {
				/* Background has an RGB color */
				int r, g, b;
				r = cell_video_attr_bg_rgb_r(colornormal);
				g = cell_video_attr_bg_rgb_g(colornormal);
				b = cell_video_attr_bg_rgb_b(colornormal);
				defaultattribute = cell_video_attr_set_fg_rgb(defaultattribute, r, g, b);
			} else
#endif
				defaultattribute = cell_video_attr_set_fg_color(defaultattribute,
						cell_video_attr_background(colornormal));
		} else {
#ifdef CK_COLORS_24BIT
			if (!cell_video_attr_fg_is_indexed(colornormal)) {
				/* Foreground has an RGB color */
				int r, g, b;
				r = cell_video_attr_fg_rgb_r(colornormal);
				g = cell_video_attr_fg_rgb_g(colornormal);
				b = cell_video_attr_fg_rgb_b(colornormal);
				defaultattribute = cell_video_attr_set_fg_rgb(defaultattribute, r, g, b);
			} else
#endif
				defaultattribute = cell_video_attr_set_fg_color(defaultattribute,
					cell_video_attr_foreground(colornormal));
		}
		break;
	case 111: /* xterm - reset attribute background */
		if ( decscnm ) {  /* Reverse screen? Set VG to colornormal FG*/
#ifdef CK_COLORS_24BIT
			if (!cell_video_attr_fg_is_indexed(colornormal)) {
				/* Foreground has an RGB color */
				int r, g, b;
				r = cell_video_attr_fg_rgb_r(colornormal);
				g = cell_video_attr_fg_rgb_g(colornormal);
				b = cell_video_attr_fg_rgb_b(colornormal);
				defaultattribute = cell_video_attr_set_bg_rgb(defaultattribute, r, g, b);
			} else
#endif
				defaultattribute = cell_video_attr_set_bg_color(defaultattribute,
						cell_video_attr_foreground(colornormal));
		} else {
#ifdef CK_COLORS_24BIT
			if (!cell_video_attr_bg_is_indexed(colornormal)) {
				/* Background has an RGB color */
				int r, g, b;
				r = cell_video_attr_bg_rgb_r(colornormal);
				g = cell_video_attr_bg_rgb_g(colornormal);
				b = cell_video_attr_bg_rgb_b(colornormal);
				defaultattribute = cell_video_attr_set_bg_rgb(defaultattribute, r, g, b);
			} else
#endif
				defaultattribute = cell_video_attr_set_bg_color(defaultattribute,
					cell_video_attr_background(colornormal));
		}
		break;
	case 112: /* xterm - reset text cursor color */
#ifdef CK_COLORS_24BIT
		if (!cell_video_attr_bg_is_indexed(savedcolorcursor)) {
			/* Background has an RGB color */
			int r, g, b;
			r = cell_video_attr_bg_rgb_r(savedcolorcursor);
			g = cell_video_attr_bg_rgb_g(savedcolorcursor);
			b = cell_video_attr_bg_rgb_b(savedcolorcursor);
			colorcursor = cell_video_attr_set_bg_rgb(savedcolorcursor, r, g, b);
		} else
#endif
			colorcursor = cell_video_attr_set_bg_color(colorcursor,
				cell_video_attr_background(savedcolorcursor));
		break;
	case 113: /* xterm - reset pointer foreground color */
	case 114: /* xterm - reset pointer background color */
	case 115: /* xterm - reset tektronix foreground */
	case 116: /* xterm - reset tektronix background */
		break;
	case 117: /* xterm - reset highlight background color */
#ifdef CK_COLORS_24BIT
		if (!cell_video_attr_bg_is_indexed(savedcolorselect)) {
			/* Background has an RGB color */
			int r, g, b;
			r = cell_video_attr_bg_rgb_r(savedcolorselect);
			g = cell_video_attr_bg_rgb_g(savedcolorselect);
			b = cell_video_attr_bg_rgb_b(savedcolorselect);
			colorselect = cell_video_attr_set_bg_rgb(colorselect, r, g, b);
		} else
#endif
			colorselect = cell_video_attr_set_bg_color(colorselect,
				cell_video_attr_background(savedcolorselect));
		break;
	case 118: /* xterm - reset tektronix cursor color */
		break;
	case 119: /* xterm - reset highlight foreground color */
#ifdef CK_COLORS_24BIT
		if (!cell_video_attr_fg_is_indexed(savedcolorselect)) {
			/* Background has an RGB color */
			int r, g, b;
			r = cell_video_attr_fg_rgb_r(savedcolorselect);
			g = cell_video_attr_fg_rgb_g(savedcolorselect);
			b = cell_video_attr_fg_rgb_b(savedcolorselect);
			colorselect = cell_video_attr_set_fg_rgb(colorselect, r, g, b);
		} else
#endif
			colorselect = cell_video_attr_set_fg_color(colorselect,
				cell_video_attr_foreground(savedcolorselect));
		break;
    }
}

/* dopu1 - process PU1 sequences (97801-5xx terminals) */
void
dopu1( void )
{
    debug(F111,"dopu1",apcbuf,apclength);
}

/* dopu2 - process PU2 sequences (97801-5xx terminals) */
void
dopu2( void )
{
    debug(F111,"dopu2",apcbuf,apclength);
    switch ( apcbuf[0] ) {
    case 'A':
        /* Load key assignment table */
        break;
    case 'B':
        /* Load one or more character generator addresses with a new */
        /* symbol ( ... = 3-byte address and 28/32-byte pattern in hex format ) */
        break;
    case 'C':
        if ( apcbuf[1] == NUL )
            ; /* Query load process for string key table */
        else
            ; /* Load string key table */
        break;
    case 'D':
        if ( apclength == 1 )
            ; /* Delete compose key table */
        else
            ; /* Load compose key table */
        break;
    case 'E':
        /* Load dead key table */
        break;
    case 'F':
        /* Load key assignment table */
        break;
    }
}

/* ------------------------------------------------------------------ */
/* dodcs - process DCS sequences (VT320 and higher)                   */
/*         sequence of apclength in apcbuf                            */
/* ------------------------------------------------------------------ */

void
dodcs( void )
{
    int pn[11];
    int i,k,l;
    int dcsnext = 0 ;
    char keydef[257] ; /* UDK defs can't be longer than 256 chars */
    char c;

    /*
     * Originally this function was only available to:
     *     tt_type_mode >= TT_VT320 && tt_type_mode <= TT_WY370
     * Compared to ISVT320() this excludes TT_97801 and TT_AAA. I have no idea
     * what those terminals implement or if there was any particular reason for
     * their exclusion, but excluding TT_VT220 was almost certainly by accient
     * as it *does* support at least one DCS sequence here - DECUDK.
     * So now we allow ISVT320() in here, plus TT_VT220 and a few others, but
     * exclude TT_97801 and TT_AAA as before just in case there was some
     * particular reason for their exclusion.
     */

    debug( F111,"DCS string",apcbuf,apclength ) ;

    if ( debses )              /* If TERMINAL DEBUG ON */
      return ;                 /* don't do anything    */
    achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
    switch ( achar ) {
    case '$':  /* as in $q - DECRQSS, or $p as in DECRSTS */
        k = 0 ;
        goto LB4003;
    case '|':  /* DECUDK */
        pn[1] = pn[2] = 0;
        k = 2;
        goto LB4003;
    case ';':           /* As in DCS ; 7 m */
        pn[1] = 0;
        k = 1;
        goto LB4002;
    default:            /* Pn - got a number */
      /*LB4001:*/
        {               /* Esc [ Pn...Pn x   functions */
            pn[1] = 0 ;
            while (isdigit(achar)) {            /* Get number */
                pn[1] = (pn[1] * 10) + achar - 48;
                achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
            }
            k = 1;
          LB4002:
            while (achar == ';') { /* get Pn[k] */
                achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                if (k < 10) k++;
                if (achar == '?')
                  achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                pn[k] = 0 ;
                while (isdigit(achar)) {                /* Get number */
                    pn[k] = (pn[k] * 10) + achar - 48;
                    achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                }
            }
            pn[k + 1] = 1;
          LB4003:
            switch (achar) { /* Third level */
            case '$':
                if (ISVT320(tt_type_mode)) {
                /* This has to be long to account for SGR at a minimum. */
#define DECRPSS_LEN 100
                char decrpss[DECRPSS_LEN];
                decrpss[0] = '\0';

                achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                switch ( achar ) {
                case 'p':
                    if (ISVT420(tt_type_mode) && k == 1 && pn[1] == 1) {
                        /* TODO: DECRSTS - Restore Terminal State */
                    } else if (k == 1 && pn[1] == 2 &&
                               (ISVT525(tt_type_mode) || ISK95(tt_type_mode))) {
                        /* DECRSTS - Restore Terminal Color Table State */
                        restore_color_table(dcsnext);
                    }
                    break;
                case 'q': {              /* DECRQSS */
                    char fmt[15];
                    memset(fmt,0,sizeof(fmt));

                    /* Resulting format string has three parameters:
                     *  %d - 0 for valid, 1 for invalid
                     *  %s - the response string including any final characters
                     */
                    if (send_c1)
                        _snprintf(fmt, sizeof(fmt), "%c%%d$r%%s%c", _DCS, _ST8);
                    else {
                        _snprintf(fmt, sizeof(fmt), "%cP%%d$r%%s%c\\", ESC, ESC);
                    }

                    /* The next set of characters are the D...D portion */
                    /* of the DECRQSS request. */
                    achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;

                    /* The Windows Terminal, and possibly a real VT525, allows
                     * parameter numbers to be here too. That is, both of these
                     * are recognised as valid:
                     *     DCS 1 $ q ' } ST
                     *     DCS $ q 1 ' } ST
                     * So if we found no parameters before the '$', check for any
                     * after the 'q' */
                    if (k == 0) { /* No parameters? Look again. */
                        pn[1] = 0;
                        while (isdigit(achar)) {            /* Get number */
                            pn[1] = (pn[1] * 10) + achar - 48;
                            achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        }
                        k = 1;
                        while (achar == ';') { /* get Pn[k] */
                            achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                            if (k < 10) k++;
                            if (achar == '?')
                              achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                            pn[k] = 0 ;
                            while (isdigit(achar)) {                /* Get number */
                                pn[k] = (pn[k] * 10) + achar - 48;
                                achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                            }
                        }
                        pn[k + 1] = 1;
                    }

                    switch ( achar ) {
                    case '}':           /* DECPRO */
                        if ( send_c1 )
                            sprintf(decrpss,"%c0$r}%c",_DCS,_ST8);
                        else
                            sprintf(decrpss,"%cP0$r}%c\\",ESC,ESC);
                        break;
                    case '$':
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case '}':       /* DECSASD */
                            _snprintf(decrpss, DECRPSS_LEN, fmt, 1,
                                decsasd == SASD_TERMINAL? "0$}" : "1$}");
                            break;
                        case '|': {     /* DECSCPP */
                            char buf[10];
                            _snprintf(buf, sizeof(buf), "%d$|", tt_cols[VTERM]);
                            _snprintf(decrpss, DECRPSS_LEN, fmt, 1, buf);
                            break;
                        }
                        case '~':       /* DECSSDT */
                            _snprintf(decrpss, DECRPSS_LEN, fmt, 1,
                                  decssdt == SSDT_BLANK ? "0$~"
                                : decssdt == SSDT_INDICATOR ? "1$~"
                                : "2$~");
                            break;
                        }
                        break;
                    case '"': {
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case 'q':       /* DECSCA */
                            _snprintf(decrpss, DECRPSS_LEN, fmt, 1,
                                attrib.unerasable? "1\"q" : "0\"q");
                            break;
                        case 'p': {     /* DECSCL */
                            int m = 0;

                            /* The 61 and 62 cases shoud never happen in practice.
                             * The only time a VT520, VT420 or presumably a VT320
                             * reports itse compatibility level at anything less than
                             * itself is if its emulating the VT100, and the VT100
                             * doesn't support DECRQSS (nor does the VT220. And so
                             * when the VT520 has been put in VT100 compatibility
                             * mode, it doesn't respond to DECRQSS.
                             */
                            switch(tt_type_mode) {
                            case TT_VT100:
                            case TT_VT102:
                                m = 61;
                                break;
                            case TT_VT220:
                            case TT_VT220PC:
                                m = 62;
                                break;
                            case TT_VT320:
                            case TT_VT320PC:
                            case TT_WY370:
                                m = 63;
                                break;
                            case TT_K95:
                            case TT_XTERM:
                            case TT_VT420:
                                m = 64;
                                break;
                            case TT_VT520:
                                m = 65;
                                break;
                            } /* tt_type_mode */

                            if (m != 0) {
                                char buf[10];
                                _snprintf(buf, sizeof(buf), "%d;%d\"p",
                                    m, send_c1 ? 2 : 1);
                                _snprintf(decrpss, DECRPSS_LEN, fmt, 1, buf);
                            } else {
                                char buf[10];
                                _snprintf(buf, sizeof(buf), "\"p");
                                _snprintf(decrpss, DECRPSS_LEN, fmt, 0, buf);
                            }

                            break;
                            } /* 'p' */
                        } /* achar */
                        break;
                    } /* '"' */
                    case 't': {          /* DECSLPP */
                        char buf[10];
                        _snprintf(buf, sizeof(buf), "%dt", tt_rows[VTERM]);
                        _snprintf(decrpss, DECRPSS_LEN, fmt, 1, buf);
                        break;
                    }
                    case 'r': {         /* DECSTBM */
                        char buf[20];
                        _snprintf(buf, sizeof(buf), "%d;%dr",
							vscrn_c_page_margin_top(VTERM),
							vscrn_c_page_margin_bot(VTERM));
                        _snprintf(decrpss, DECRPSS_LEN, fmt, 1, buf);
                        break;
                    }
                    case '|':           /* DECTTC */
                        if ( send_c1 )
                            sprintf(decrpss,"%c0$r|%c",_DCS,_ST8);
                        else
                            sprintf(decrpss,"%cP0$r|%c",ESC,ESC);
                        break;
                    case '\'':
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case 's':       /* DECTLTC */
                            if ( send_c1 )
                                sprintf(decrpss,"%c0$r\'s%c",_DCS,_ST8);
                            else
                                sprintf(decrpss,"%cP0$r\'s%c\\",ESC,ESC);
                            break;
                        }
                        break;
                    case 'm': {          /* SGR */
                        char sgrbuf[80];
                        int sgrbuf_len=0;

                        memset(sgrbuf,0,sizeof(sgrbuf));

                        strcat(sgrbuf, "0");

                        if (attrib.bold)  strcat(sgrbuf, ";1");

                        if (ISSCO(tt_type_mode)) {
                            /* TODO: 2;fg;bg;  - fg/bg color (SCOANSI only)
                               (If the FG/BG colors are not the default) */
                        } else if (attrib.dim) {
                            strcat(sgrbuf, ";2");
                        }

                        if (attrib.italic) strcat(sgrbuf, ";3");
                        if (attrib.underlined) strcat(sgrbuf, ";4");
                        if (attrib.blinking) strcat(sgrbuf, ";5");
                        if (attrib.reversed) strcat(sgrbuf, ";7");
                        if (attrib.invisible) strcat(sgrbuf, ";8");
						if (attrib.crossedout) strcat(sgrbuf, ";9");

#ifdef COMMENT
                        /* We don't really have a *good* way of knowing if these
                         * were given previously. The code below is at best an
                         * approximation - really we need these SGR parameters
                         * to set an attribute or something. But is unlikely that
                         * these terminal types actually supported DECRQSS in the
                         * real world (the linux console terminal in 2025 doesn't
                         * claim to), so its unlikely that any applications actually
                         * using these SGR parameters would expect DECRQSS to do
                         * anything. */

                        if (ISANSI(tt_type_mode) || ISBEOS(tt_type_mode)) {
                            if (!sco8bit && !crm && !attrib.graphic && GR = &G[1])
                                sgrcat(sgrbuf, ";10");
                        } else if (ISLINUX(tt_type_mode) || ISQANSI(tt_type_mode) {
                            if (!sco8bit && !crm)
                                sgrcat(sgrbuf, ";10");
                        }

                        if ( ISANSI(tt_type_mode) ) {
                            if (!sco8bit && crm && GR == &G[2]) strcat(sgrbuf, ";11");
                        } else if (ISLINUX(tt_type_mode) || ISQANSI(tt_type_mode)) {
                            if (sco8bit && crm) strcat(sgrbuf, ";11");
                        }

                        if (ISLINUX(tt_type_mode) && sco8bit && crm && attrib.graphic = FALSE) {
                            strcat(sgrbuf, ";12");
                        }

                        if ((ISANSI(tt_type_mode) || ISBEOS(tt_type_mode)) &&
                            sco8bit && !crm && !attrib.graphic && GR == &G[3]) {
                            strcat(sgrbuf, ";17");
                        } else if (ISQANSI(tt_type_mode) && sco8bit && !crm) {
                            strcat(sgrbuf, ";17");
                        }
#endif

                        /* Now we do color. Foreground first. */
#ifdef CK_COLORS_24BIT
                        if (!cell_video_attr_fg_is_indexed(attribute)) {
                            char fgbuf[20];
                            int r, g, b;

                            memset(fgbuf,0,sizeof(fgbuf));

                            r = cell_video_attr_fg_rgb_r(attribute);
                            g = cell_video_attr_fg_rgb_g(attribute);
                            b = cell_video_attr_fg_rgb_b(attribute);

                            if (cell_video_attr_fg_is_indexed(defaultattribute) ||
                                cell_video_attr_fg_rgb_r(defaultattribute) != r ||
                                cell_video_attr_fg_rgb_g(defaultattribute) != g ||
                                cell_video_attr_fg_rgb_b(defaultattribute) != b) {

                                _snprintf(fgbuf, sizeof(fgbuf), ";38:2:0:%d:%d:%d", r, g, b);
                                strcat(sgrbuf, fgbuf);
                            }
                        } else
#endif
                        {
                            int fg = cell_video_attr_foreground(attribute);
                            int def_fg = cell_video_attr_foreground(defaultattribute);
                            char fgbuf[10];

                            memset(fgbuf,0,sizeof(fgbuf));

                            if (fg != def_fg) {
                                if (fg > 15) {
                                    _snprintf(fgbuf, sizeof(fgbuf), ";38:5:%d", fg);
                                } else if (fg > 7) {
                                    fg -= 8;
                                    fg = sgrindex[fg%8];
                                    _snprintf(fgbuf, sizeof(fgbuf), ";%d", 90+fg);
                                } else {
                                    fg = sgrindex[fg%8];
                                    _snprintf(fgbuf, sizeof(fgbuf), ";%d", 30+fg);
                                }
                                strcat(sgrbuf, fgbuf);
                            }
                        }

                        /* Now we do color. Now backgroudn. */
#ifdef CK_COLORS_24BIT
                        if (!cell_video_attr_bg_is_indexed(attribute)) {
                            char bgbuf[20];
                            int r, g, b;

                            memset(bgbuf,0,sizeof(bgbuf));

                            r = cell_video_attr_bg_rgb_r(attribute);
                            g = cell_video_attr_bg_rgb_g(attribute);
                            b = cell_video_attr_bg_rgb_b(attribute);

                            if (cell_video_attr_bg_is_indexed(defaultattribute) ||
                                cell_video_attr_bg_rgb_r(defaultattribute) != r ||
                                cell_video_attr_bg_rgb_g(defaultattribute) != g ||
                                cell_video_attr_bg_rgb_b(defaultattribute) != b) {

                                _snprintf(bgbuf, sizeof(bgbuf), ";48:2:0:%d:%d:%d", r, g, b);
                                strcat(sgrbuf, bgbuf);
                            }
                        } else
#endif
                        {
                            int bg = cell_video_attr_background(attribute);
                            char bgbuf[10];

                            memset(bgbuf,0,sizeof(bgbuf));

                            if (bg != cell_video_attr_background(defaultattribute)) {
                                if (bg > 15) {
                                    _snprintf(bgbuf, sizeof(bgbuf), ";48:5:%d", bg);
                                } else if (bg > 7) {
                                    bg -= 8;
                                    bg = sgrindex[bg%8];
                                    _snprintf(bgbuf, sizeof(bgbuf), ";%d", 100+bg);
                                } else {
                                    bg = sgrindex[bg%8];
                                    _snprintf(bgbuf, sizeof(bgbuf), ";%d", 40+bg);
                                }
                            }
                            strcat(sgrbuf, bgbuf);
                        }

                        /* Append final character (overwriting the trailing ';'),
                         * then assemble full DECRPSS response */
                        strcat(sgrbuf, "m");

                        _snprintf(decrpss, DECRPSS_LEN, fmt, 1, sgrbuf);

                        break;
                        }
                    case 's':           /* DECSLRM - Set Left and Right Margins */
						if (IS_DECLRMM_AVAILABLE(tt_type_mode)) {
							char buf[200];
                            _snprintf(buf, sizeof(buf), "%d;%ds",
								vscrn_c_page_margin_left(VTERM),
								vscrn_c_page_margin_right(VTERM));
                            _snprintf(decrpss, DECRPSS_LEN,
                                        fmt, 1, buf);
						}
                        break;
                    case '*':
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case 'x':       /* DECSACE - Select Attrib Change Extent */
                            _snprintf(decrpss, DECRPSS_LEN, fmt, 1,
                                decsace? "2*x" : "1*x");
                            break;
                        case '|':       /* DECSNLS - Set Num Lines Per Screen */
                            if (ISVT525(tt_type_mode)) {
                                char buf[10];
                                _snprintf(buf, sizeof(buf), "%d*|", tt_rows[VTERM]);
                                _snprintf(decrpss, DECRPSS_LEN,
                                        fmt, 1, buf);
                            }
                            break;
                        }
                        break;
                    case '+':
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case 'q':       /* DECELF - Enable Local Functions */
                            if ( send_c1 )
                                sprintf(decrpss,"%c1$r+q%c",_DCS,_ST8);
                            else
                                sprintf(decrpss,"%cP1$r+q%c\\",ESC,ESC);
                            break;
                        case 'r':       /* DECSMKR - Select modifier key reporting */
                            if ( send_c1 )
                                sprintf(decrpss,"%c1$r+r%c",_DCS,_ST8);
                            else
                                sprintf(decrpss,"%cP1$r+r%c\\",ESC,ESC);
                            break;
                        }
                        break;
                    case '=':
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case '}':       /* DECLFKC - Local Function Key Control */
                            if ( send_c1 )
                                sprintf(decrpss,"%c1$r=}%c",_DCS,_ST8);
                            else
                                sprintf(decrpss,"%cP1$r=}%c\\",ESC,ESC);
                            break;
                        }
                        break;
                    case ')': {
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case '{': {    /* DECSTGLT */
                            if (ISVT525(tt_type_mode)) {
                                char buf[10];
                                _snprintf(buf, sizeof(buf), "%d){", decstglt);
                                _snprintf(decrpss, DECRPSS_LEN,
                                        fmt, 1, buf);
                            }
                            break;
                        } /* '}' */
                        } /* achar */
                        break;
                    } /* ')' */
                    case SP: {
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case 'p': {    /* DECSSCLS */
                            int decsscls = -1;
#ifdef KUI
                            /* The VT520 reports a recent speed change as though
                             * it has already taken effect */
                            int speed = smooth_speed_pending == -1
                                ? smooth_speed : smooth_speed_pending;

                            if (ISK95(tt_type_mode)) {
                                if (scrollmode == TTS_JUMP) decsscls = 9;
                                else if (speed <= 3) decsscls = 0;
                                else if (speed <= 6) decsscls = 1;
                                else if (speed <= 9) decsscls = 2;
                                else if (speed <= 12) decsscls = 3;
                                else if (speed <= 18) decsscls = 4;
                                else if (speed <= 22) decsscls = 5;
                                else if (speed <= 27) decsscls = 6;
                                else if (speed <= 31) decsscls = 7;
                                else if (speed <= 36) decsscls = 8;
                            } else if (ISVT520(tt_type_mode)) {
                                /* ?4l, 9 = 9
                                 * ?4h, 0...3 = 2
                                 * 4..8 = 4 */
                                if (scrollmode == TTS_JUMP) decsscls = 9;
                                else if (scrollmode == TTS_SMOOTH_2 ||
                                         speed <= 9)
                                    decsscls = 2;
                                else decsscls = 4;
                            }
#endif /* KUI */
                            if (decsscls >= 0) {
                                char buf[10];
                                _snprintf(buf, sizeof(buf), "%d p", decsscls);
                                _snprintf(decrpss, DECRPSS_LEN,
                                        fmt, 1, buf);
                            }
                        } /* 'p' */
                        case 'q': {    /*  DECSCUSR  */
                            _snprintf(decrpss, DECRPSS_LEN, fmt, 1,
                                 (tt_cursor == TTC_BLOCK && tt_cursor_blink == 1) ? "1 q"
                                :(tt_cursor == TTC_BLOCK && tt_cursor_blink == 0) ? "2 q"
                                :(tt_cursor == TTC_ULINE && tt_cursor_blink == 1) ? "3 q"
                                :(tt_cursor == TTC_ULINE && tt_cursor_blink == 0) ? "4 q"
                                :"0 q"
                                );
                            break;
                        } /* 'q' */
                        case 't': {     /* DECSWBV */
                            if (ISVT520(tt_type_mode) || ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                extern int beepvolume;
                                int val = 8; /* high */
                                char buf[10];

                                if (tt_bell == XYB_NONE) {
                                    val = 1;
                                }
#ifdef NT
                                else if (tt_bell == XYB_AUD | XYB_MIDI) {
                                    val = beepvolume == BEEP_VOLUME_LOW ? 4 : 8;
                                }
#endif
                                _snprintf(buf, sizeof(buf), "%d t", val);
                                _snprintf(decrpss, DECRPSS_LEN,
                                        fmt, 1, buf);
                                /* off is 1, low is 4, high is 8 */
                            }
                        } /* 't' */
                        } /* achar */
                        break;
                    } /* SP */
                    case ',': {
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        switch ( achar ) {
                        case 'x':     /*  DECSPMA */
                            if (ISVT520(tt_type_mode)) {
                                char buf[20];
                                _snprintf(buf, sizeof(buf), "%d;0;0;0,x",
                                    term_max_page(VTERM) + 1);
                                _snprintf(decrpss, DECRPSS_LEN,
                                         fmt, 1, buf);
                            }
                            break;
#ifdef KUI
                        case 'z':     /*  DECDLDA */
                            if (ISVT520(tt_type_mode)) {
                                char buf[20];
                                /* TODO: I am *assuming* the VT525 still
                                 * supports querying DECDLDA via DECRQSS even if
                                 * it doesn't implement DECDLDA itself. So for
                                 * VT525 we report 2 buffers as that terminal
                                 * always supports two (which is why it doesn't
                                 * implement DECDLDA). */
                                _snprintf(buf, sizeof(buf), "%d,z",
                                    ISVT525(tt_type_mode) ? 2 : decdlda);
                                _snprintf(decrpss, DECRPSS_LEN,
                                         fmt, 1, buf);
                            }
                            break;
#endif /* KUI */
                        case '}': {    /*  DECATC  */
                            char buf[20];

                            if (k >= 1 && pn[1] >= 0 && pn[1] <= 15 && ISVT525(tt_type_mode)) {
                                cell_video_attr_t att = decatc_colors[pn[1]];

                                _snprintf(buf, sizeof(buf), "%d;%d;%d,}",
                                    pn[1],
                                    color_index_from_vio(cell_video_attr_foreground(att)),
                                    color_index_from_vio(cell_video_attr_background(att)));
                                _snprintf(decrpss, DECRPSS_LEN,
                                         fmt, 1, buf);
                            } else {
                                _snprintf(decrpss, DECRPSS_LEN,
                                         fmt, 0, ",}");
                            }

                            break;
                        } /* '}' */
						case '|': {    /*  DECAC  */
							if (k >= 1 && pn[1] >= 1 && pn[1] <= 2 && ISVT525(tt_type_mode)) {
                                char buf[20];
								cell_video_attr_t att = cell_video_attr_init_vio_attribute(0x00);

								if (pn[1] == 1) att = defaultattribute;
								/* TODO: pn[1] == 2: Window Frame */

                                _snprintf(buf, sizeof(buf), "%d;%d;%d,|",
                                    pn[1],
                                    color_index_from_vio(cell_video_attr_foreground(att)),
                                    color_index_from_vio(cell_video_attr_background(att)));
                                _snprintf(decrpss, DECRPSS_LEN,
                                         fmt, 1, buf);
							} else {
                                _snprintf(decrpss, DECRPSS_LEN,
                                         fmt, 0, ",|");
                            }
							break;
						} /* '|' */
                        } /* achar */
                        break;
                    } /* ',' */
                    } /* end switch */

                    /* Unrecognised request */
                    if ( decrpss[0] == '\0') {
                        if ( send_c1 )
                            sprintf(decrpss,"%c0$r%c",_DCS,_ST8);
                        else
                            sprintf(decrpss,"%cP0$r%c\\",ESC,ESC);
                    }

                    sendchars(decrpss,strlen(decrpss));
                    break;
                    }  /* 'q' - DECRQSS */
                } /* switch on character afer '$' */
				break;
            } /* $ */
            case '{':      /* DECDLD - Soft character set */
#ifdef KUI
                if (k < 8) pn[8] = 0;
                if (k < 7) pn[7] = 0;
                if (k < 6) pn[6] = 0;
                if (k < 5) pn[5] = 0;
                if (k < 4) pn[4] = 0;
                if (k < 3) pn[3] = 0;
                if (k < 2) pn[2] = 0;
                if (k < 1) pn[1] = 0;
                decdld(pn[1], pn[2], pn[3], pn[4], pn[5], pn[6], pn[7], pn[8],
                   apcbuf+dcsnext, apclength - dcsnext);
#endif /* KUI */
                break;
            case '|': {    /* DECUDK */
                int key = 0 ;
                /* pn[1] - Clear keys: 0 All, 1 One */
                /* pn[2] - Lock keys:  0 Lock, 1 no Lock */
                if ( k<2 )
                    pn[2] = 1 ;
                if ( k<1 )
                    pn[1] = 0 ;

                if ( udklock )
                    return;  /* do nothing if the UDKs are locked */

                if ( pn[1] == 0 ) { /* Clear all key defs */
                    udkreset() ;
                }

                while ( dcsnext < apclength ) {
                    /* look for patterns of XX/string; */

                    key=0;
                    /* which key to assign to? */
                    achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                    if ( achar == ';' )
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;

                    while (isdigit(achar)) {                /* Get number */
                        key = (key * 10) + achar - 48;
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                    }

                    /* Check for proper separator */
                    if ( achar != '/') {
                        /* if error, call cwrite() on rest of DCS         */
                        /* including ST.  Actually, in a real VT terminal */
                        /* we wouldn't even wait until this point to      */
                        /* determine if there was an error.  We would do  */
                        /* this as the data is received.                  */
                        while ( achar ) {
                            cwrite(achar);
                            achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        }
                        cwrite(ESC);
                        cwrite('\\');
                        return ;
                    }

                    /* Get the key definition */
                    l = 0 ; /* characters in definition */
                    i = 0 ; /* which pass? */
                    while ( apcbuf[dcsnext] != ';' &&
                            dcsnext < apclength ) {
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        c = 0 ;
                        if ( isxdigit(achar) )
                        {
                            if ( isdigit(achar) )
                                c = achar - '0' ;
                            else if ( islower(achar) )
                                c = achar - 'a' + 10 ;
                            else
                                c = achar - 'A' + 10 ;
                        }   
                        if ( i ) {
                            keydef[l] = (keydef[l]<<4)|c ;
                            l++ ;
                            keydef[l] = '\0' ;
                            i = 0 ;
                        }
                        else {
                            keydef[l] = c ;
                            i = 1 ;
                        }
                    }   

                    if ( i == 1 ||
                         apcbuf[dcsnext] != ';' &&
                         dcsnext < apclength ){
                        /* if error, call cwrite() on rest of DCS         */
                        /* including ST.  Actually, in a real VT terminal */
                        /* we wouldn't even wait until this point to      */
                        /* determine if there was an error.  We would do  */
                        /* this as the data is received.                  */
                        while ( achar ) {
                            cwrite(achar);
                            achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        }
                        cwrite(ESC);
                        cwrite('\\');
                        return ;
                    }

                    i = -1 ;
                    switch ( key ) {
                        /* DEC couldn't make it easy, could they */
                    case 11: i = 0 ; break ;
                    case 12: i = 1 ; break ;
                    case 13: i = 2 ; break ;
                    case 14: i = 3 ; break ;
                    case 15: i = 4 ; break ;
                    case 17: i = 5 ; break ;
                    case 18: i = 6 ; break ;
                    case 19: i = 7 ; break ;
                    case 20: i = 8 ; break ;
                    case 21: i = 9 ; break ;
                    case 23: i = 10 ; break ;
                    case 24: i = 11 ; break ;
                    case 25: i = 12 ; break ;
                    case 26: i = 13 ; break ;
                    case 28: i = 14 ; break ;
                    case 29: i = 15 ; break ;
                    case 31: i = 16 ; break ;
                    case 32: i = 17 ; break ;
                    case 33: i = 18 ; break ;
                    case 34: i = 19 ; break ;
                    }
                    if ( i>= 0 )
                    {
                        if ( udkfkeys[i] ) {
                            free( udkfkeys[i] ) ;
                            udkfkeys[i]=NULL;
                        }
                        if ( strlen(keydef) )
                            udkfkeys[i] = strdup(keydef) ;
                    }   
                    }   

                if ( !pn[2] )
                    udklock = TRUE ;
                break;
            }   /* | */
            case '+': {
                achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                switch ( achar ) {
                case 'm': {  /* URL or UNC attribute */
                    int  quote = 0;
                    char * link = NULL, *p;

                    if ( k < 1 )
                        pn[1] = 0;

                    switch ( pn[1] ) {
                    case 0:     /* End URL or UNC link */
                        debug(F100,"URL/UNC link attribute removed","",0);
                        if ( debses )
                            break;
                        attrib.hyperlink = FALSE;
                        attrib.linkid = 0;
                        break;
                    case 1:     /* Begin URL link */
                    case 2:     /* Begin UNC link */
                        link = (char *) malloc(apclength - dcsnext + 1);
                        if ( !link )
                            break;
                        
                        p = link;
                        achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        quote = (achar == '"');
                        if ( quote )
                            achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;

                        while ( achar && (!quote || (quote && achar != '"') ))
                        {
                            *p++ = achar;
                             achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        }
                        *p = '\0';
                        switch ( pn[1] ) {
                        case 1: 
                            debug(F110,"URL link assigned",link,0);
                            if ( debses ) {
                                free(link);
                                break;
                            }
                            attrib.hyperlink = TRUE;
                            attrib.linkid = hyperlink_add(HYPERLINK_URL, link);
                            break;
                        case 2:
                            debug(F110,"UNC link assigned",link,0);
                            if ( debses ) {
                                free(link);
                                break;
                            }
                            attrib.hyperlink = TRUE;
                            attrib.linkid = hyperlink_add(HYPERLINK_UNC, link);
                            break;
                        default:
                            debug(F110,"unknown link type",link,pn[1]);
                            free(link);
                        }
                        break;
                    }
                    break;
                }   /* m */
                }   /* achar */
                break;
            }  /* + */
			case '!': {
				achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                switch ( achar ) {
                case 'z': {  /* DECDMAC - Define Macro */
					/* VT level 4 or higher only. Macros can not define macros*/
					if (ISVT420(tt_type_mode) && !vt_macro_invocation) {
						int macid;
						int delact = 0;
						int fmt = 0;
						/* pn[1] is the macro ID
				     	 * pn[2] is optional delete action, default 0
					 	 * pn[3] is optional format, default ASCII
					 	 */

						/* Macro ID required */
						if (k < 1) break;
						macid = pn[1];

						if (k > 1)
							delact = pn[2];
						if (k > 2)
							fmt = pn[3];

						/* Check macro ID is valid */
						if (macid < 0 || macid > 63) break;

						/* Check delete action is valid. */
						if (delact < 0 || delact > 1) break;

						/* Check format is valid */
						if (fmt < 0 || fmt > 1) break;

						if (delact == 0) {
							/* Delete this macro if it exists */
							if (vt_macro_definitions[macid]) {
								vt_macro_size -= strlen(vt_macro_definitions[macid]);
								free(vt_macro_definitions[macid]);
								vt_macro_definitions[macid] = NULL;
							}
						} else if (delact == 1) {
							/* Clear *all* macro definitions */
							vt_macro_clear();
						}

						if (fmt == 0) {
							/* ASCII text format. Graphic characters only. That
							 * is: SP through ~ inclusive
							 * and: 10/00 through 15/15 (whatever those codes
							 * turn out to be). Characters 8-13 (BS-CR) are
							 * ignored. */

							char* mac = (char*)malloc(apclength - dcsnext + 1);
							char* p = mac;
							int maclen;
							memset(mac, 0, apclength - dcsnext + 1);

							achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
							while ( achar )
                        	{
								if ((achar >= ' ' && achar <= '~') ||
									(achar >= 160 && achar <= 255)) {
                            		*p++ = achar;
								} /* Else ignore it - the VT520 seems to */
                             	achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        	}

							maclen = strlen(mac);
							if (maclen > 0 && vt_macro_size+maclen < MACRO_SIZE_LIMIT(tt_type_mode)) {
								vt_macro_size += maclen;
								vt_macro_definitions[macid] = mac;
							} else {
								/* Error - out of macro space or zero length macro */
								free(mac);
							}
						} else {
							/* HEX format. Two hex digits decode to one
						     * character. NULLs should be ignored.
							 * If a ! is encountered, the format is:
							 *   ! Pn ; D....D ;
							 * Where Pn indicates the number of times the HEX
							 * string D...D should be repeated.
							 */

							/* We may need to run though the string twice - once
							 * to figure out how much memory we need to allocate
							 * taking into account repetitions, etc, and again to
							 * actually decode and expand the macro.
							 */

							int expanded_length = 0; /* in hex digits to start */
							int macstart = dcsnext;
							char* mac = 0;
							char* p = 0;
							int repeat_count = 1;
							int in_repetition = 0;
							char hex[3] = "  ";

							/* validate the string and compute size when
						     * repetitions are expanded */
							achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
							while ( achar )
                        	{
								if (achar == '!') {
									/* Number and semicolon should follow... */
									repeat_count = 0;
									achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
									while (isdigit(achar)) {                /* Get number */
                    					repeat_count = (repeat_count * 10) + achar - 48;
                    					achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                					}

									/* skip over the semicolon... */
									if (achar == ';') {
										achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
									} else {
										/* Error - expected a semicolon */
										debug(F101, "DECDMAC - expected semicolon, got", "", achar);
										debug(F101, "DECDMAC - ... at position", "", dcsnext);
										expanded_length = -1;
										break;
									}

									/* The repeat count is optional and indicates
									 * a single occurrence of the sequence. */
									if (repeat_count == 0) {
										repeat_count = 1;
									}

									in_repetition = 1;

									continue;
								} else if (achar == ';') {
									/* The VT420 rejects macro definitions that
									 * contain unexpected semicolons not
									 * associated with a repetition, while the
									 * VT520 just throws them away */
									if (!ISVT520(tt_type_mode) &&  in_repetition == 0) {
										debug(F101, "DECDMAC unexpected semicolon at position", "", dcsnext);
										expanded_length = -1;
										break;
									}
									in_repetition = 0;
									repeat_count = 1;
									achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
									continue;
								}

								if ((achar >= 48 && achar <= 57) ||   /* 0-9 */
									(achar >= 65 && achar <= 70) ||   /* A-F */
									(achar >= 97 && achar <= 102)) {  /* a-f */

									expanded_length += repeat_count;
								} else if ((achar >= 9 && achar <= 13)) {
									/* Ignored: HR - CR are allowed to be used
									 * for formatting the DCS sequence. */
								} else {
									/* Error */
									debug(F101, "DECDMAC invalid character", "", achar);
									expanded_length = -1;
									break;
								}

                             	achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        	}

							if (expanded_length <= 0) break; /* Nothing to do */

							if (expanded_length % 2) {
								/* Error - Must be two hex digits per character */
								debug(F100, "DECDMAC invalid hex format", "", 0);
								break;
							}

							/* to bytes: two hex digits = 1 byte */
							expanded_length = expanded_length / 2;

							mac = (char*)malloc(expanded_length + 1);
							memset(mac, 0, expanded_length + 1);
							dcsnext = macstart;
							p = mac;

						    /* Ensure a semicolon appears at the end so that
							 * repeat sequences are terminated properly */
							if (apcbuf[apclength - 1] != ';' &&
								apclength < apcbuflen) {

								apcbuf[apclength++] = ';';
								apcbuf[apclength++] = '\0';
							}

							/* Expand the macro! */
							repeat_count = 1;
							achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
							while ( achar )
                        	{

								if (achar == '!') {
									/* Number and semicolon should follow... */
									repeat_count = 0;
									achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
									while (isdigit(achar)) {                /* Get number */
                    					repeat_count = (repeat_count * 10) + achar - 48;
                    					achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                					}

									/* skip over the semicolon... */
									if (achar == ';') {
										macstart = dcsnext;
										achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
									}
									continue;
								} else if (achar == ';') {
									if (repeat_count > 1) {
										/* Rewind and do it again! */
										repeat_count -= 1;
										dcsnext = macstart;
									}
									achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
									continue;
								}

								if ((achar >= 48 && achar <= 57) ||   /* 0-9 */
									(achar >= 65 && achar <= 70) ||   /* A-F */
									(achar >= 97 && achar <= 102)) {  /* a-f */

									if (hex[0] == ' ') {
										hex[0] = (char)achar;
									} else {
										char thechar;
										hex[1] = (char)achar;
										thechar = (char)strtol(hex, NULL, 16);
										hex[0] = ' ';

										/* Throw away null characters - these
										 * can't appear in the expanded macro */
										if (thechar != '\0') *p++ = thechar;
									}
								}

                             	achar = (dcsnext<apclength)?apcbuf[dcsnext++]:0;
                        	}

							expanded_length = strlen(mac);
							if (vt_macro_size+expanded_length < MACRO_SIZE_LIMIT(tt_type_mode)) {
								vt_macro_size += expanded_length;
								vt_macro_definitions[macid] = mac;
							} else {
								/* Error - out of macro space */
								free(mac);
							}
						}
					} /* ISVT420 */
				} /* z - DECDMAC */
				} /* fourth level */
			}  /* ! */
            }   /* third level */
        }
    }
}

void
process_canceled_decdld() {
    /* The VT220 and up will process a DECDLD right up to the CAN or SUB. To
     * the user, it is as though the CAN/SUB is treated as an ST (though all
     * but the VT220-420 will also display a reverse question mark for SUB).
     * This likely isn't *intentional* behaviour, but rather just a case of
     * these terminals not being able to spend memory on guarding against a
     * partial font download (would require downloading to a temporary space so
     * as to not overwrite the existing font until the new one is received
     * fully). But the why doesn't matter now - it only matters how these
     * things actually behave. So figure out if we're dealing with a DECDLD and
     * if we are, process what we've got as the real terminals do. */
    if (ISVT220(tt_type) && !debses) {
        int i;
        for (i = 0; i < apclength; i++) {
            /* Scan through the buffer looking for zero or more
             * parameters followed by a '{'. Any other characters would
             * not be a valid DECDLD */
            char c = apcbuf[i];
            if (isdigit(c)) continue; /* parameter */
            if (c == ';') continue;   /* parameter separator */
            if (c == '{') {           /* DECDLD */
                dodcs();
            }
            break;
        }

    }
}

#endif /* CK_APC */

/* ------------------------------------------------------------------ */
/* cwrite - check and process escape sequence                         */
/* ------------------------------------------------------------------ */


void
debugses( unsigned char ch )
{
    static char old_c = 0;
    static int  deb_wrap = 0;

    if (debses && !f_pushed) {          /* Session debugging */
        unsigned char ch8 = f_popped ? ((ch ^ 0x40) | 0x80) : ch;
        int tt_wrap_sav = tt_wrap;
        tt_wrap = 0;

        deb_wrap = wherex[VTERM] >= VscrnGetWidth(VTERM);
        if (ch8 < 32 && !literal_ch) {  /* C0 Control character */
            attribute = colordebug;     /* Use underline color */
            if (decscnm)                /* Handle flipped screen */
              attribute = swapcolors(attribute);
            wrtch((char)(ch8 | 64));    /* Write corresponding letter */
        } else if (ch8 == 127) {        /* DEL */
            attribute = colordebug;     /* Use underline color */
            if (decscnm)                /* Handle flipped screen */
              attribute = swapcolors(attribute);
            wrtch('?');                 /* question mark */
        } else if (ch8 > 127 && ch8 < 160 && !literal_ch) { /* C1 control */
            attribute = colordebug;     /* Use underline color */
            ch8 = (ch8 ^ 0x40) & 0x7F ;
            if (!decscnm)               /* Handle flipped screen */
              attribute = swapcolors(attribute);
            wrtch(ch8);                 /* The character itself */
        } else if (escstate != ES_NORMAL) { /* Part of Esc sequence */
            attribute = swapcolors(defaultattribute); /* Reverse video */
            wrtch(ch8);
        } else {                        /* Regular character */
            attribute = defaultattribute; /* Normal colors */
            if (tn_bold) attribute = cell_video_attr_with_fg_intensity_toggled(attribute); /* (only for TELNET debugging...) */
            wrtch(ch8);
        }
        if (deb_wrap ||
             ch8 == LF && old_c == CK_CR) { /* Break lines for readability */
            attribute = defaultattribute;
            wrtch(CK_CR);
            wrtch(LF);
        }
        old_c = ch8;                    /* Remember this character */
                                        /* for CRLF matching. */
        tt_wrap = tt_wrap_sav;
    }
}

void
cwrite(unsigned short ch) {             /* Used by ckcnet.c for */
                                        /* TELNET options debug display. */
    static int vt52esclen = 0 ;
/*
   Edit 190.
   New code, supporting APC, and integrating escape sequence state switching
   that was formerly done, but not used to good advantage, in chkaes().  The
   additional complexity comes from the fact that ESC is not used only to
   commence escape sequences, but also, in the case of APC, OSC, PM, etc, to
   terminate them.  New code also supports session debugging.

   Edit 192.
   New code supporting auto-download for Zmodem and Kermit protocols.
*/

	if (debses)
    	debugses( ch ) ;                    /* Session debugging */

#ifdef CKLEARN
    if (learning)
    	learnnet(ch);
#endif /* CKLEARN */

#ifndef NOXFER
    /* if Auto-download C0 conflicts are not being processed, stop now */
    if ( (!adl_kc0 && ch == stchr) || (!adl_zc0 && ch == CAN) )
         return;
#endif /* NOXFER */

#ifdef NOTERM
    if (!debses)
        wrtch(ch);
    return;
#else /* NOTERM */
    /* Unless we are parsing a terminal type based upon ANSI X3.64-1979 */
    /* this is as far as we go. */

    if (tt_type_mode == TT_NONE) {
        if (!debses)
            wrtch(ch);
        return;
    }

    if ( ISWYSE(tt_type_mode) )
    {
        wyseascii(ch) ;
        return ;
    }

    if ( ISDG200(tt_type_mode) )
    {
        dgascii(ch) ;
        return ;
    }

    if ( ISHP(tt_type_mode) )
    {
        hpascii(ch);
        return ;
    }

    if ( ISHZL(tt_type_mode) )
    {
        hzlascii(ch) ;
        return ;
    }

    if ( ISADM3A(tt_type_mode) || ISADM5(tt_type_mode) ) {
        admascii(ch);
        return;
    }

    if (ISREGENT25(tt_type_mode)) {
        addsascii(ch);
        return;
    }

    if ( ISVC(tt_type_mode) )
    {
        vcascii(ch);
        return;
    }

    if ( ISIBM31(tt_type_mode) )
    {
        i31ascii(ch);
        return ;
    }

    if ( ISQNX(tt_type_mode) ) {
        qnxascii(ch);
        return;
    }

    if ( ISTVI(tt_type_mode) )
    {
        tviascii(ch);
        return ;
    }

    if ( ISBA80(tt_type_mode) && ba80_fkey_read ) {
        extern char fkeylabel[16][32];
        if ( ba80_fkey_read < 0 ) {
            int i=0;
            ba80_fkey_read = (ch - '0') * 10;
            ba80_fkey_ptr = NULL;
            for ( i=0;i<16;i++ )
                fkeylabel[i][0] = NUL;
        }
        else if ( ba80_fkey_read % 10 == 0 ) {
            if ( ba80_fkey_ptr )
                *ba80_fkey_ptr = NUL;
            if ( isdigit(ch) )
                ba80_fkey_ptr = &fkeylabel[ch-'1'][0];
            ba80_fkey_read--;
        } else {
            if ( ba80_fkey_ptr ) {
                *ba80_fkey_ptr = ch;
                ba80_fkey_ptr++;
            }
            ba80_fkey_read--;
        }
        return;
    }

    if ( ISVTNT(tt_type_mode) && !debses && !tn_deb) {
        /* Microsoft VTNT does not start using raw WinCon structs until after */
        /* the IAC SB TERMINAL-TYPE IS VTNT IAC SE has been sent to the host. */
        /* Until that time we just treat the data as ANSI X3.64 based.        */

        if ( ttnum == -1 )
            vt100(ch);
        else {
            PCONSOLE_SCREEN_BUFFER_INFO pScrnBufInf = NULL;
            PCOORD pCursor = NULL;
            PCOORD pBufCoord = NULL;
            PCOORD pBufSz = NULL;
            PSMALL_RECT pWriteRegion = NULL;
            PCHAR_INFO pCharInfo = NULL;

            if ( vtnt_index < vtnt_read && vtnt_index < VTNT_BUFSZ) {
                vtnt_buf[vtnt_index++] = ch;
                if ( vtnt_index == VTNT_MIN_READ ) {
                    int h_vtnt, w_vtnt;
#ifdef COMMENT
                    int szchng = 0;
#endif /* COMMENT */

                    ckhexdump("VTNT MIN_READ",vtnt_buf,VTNT_MIN_READ);

                    /* Figure out how much more data we need to read */
                    pScrnBufInf = (PCONSOLE_SCREEN_BUFFER_INFO) vtnt_buf;
                    pCursor = (PCOORD) ((PCHAR) pScrnBufInf
                                      + sizeof(CONSOLE_SCREEN_BUFFER_INFO));
                    pBufCoord = (PCOORD) ((PCHAR) pCursor + sizeof(COORD));
                    pBufSz = (PCOORD) ((PCHAR) pBufCoord + sizeof(COORD));
                    pWriteRegion = (PSMALL_RECT) ((PCHAR) pBufSz
                                                   + sizeof(COORD));

#ifdef COMMENT
                    debug(F100,"VTNT Using pBufSz for Dimensions","",0);
                    w_vtnt = pBufSz->X;
                    h_vtnt = pBufSz->Y;
#else /* COMMENT */
#ifndef COMMENT2
                    debug(F100,"VTNT Using pScrnBufInf for Dimensions","",0);
                    w_vtnt = pScrnBufInf->dwSize.X;
                    h_vtnt = pScrnBufInf->dwSize.Y;
#else /* COMMENT2 */
                    debug(F100,"VTNT Using WriteRegion for Dimensions","",0);
                    w_vtnt = pWriteRegion->Right - pWriteRegion->Left + 1;
                    h_vtnt = pWriteRegion->Bottom - pWriteRegion->Top + 1;
#endif /* COMMENT2 */
#endif /* COMMENT */
                    vtnt_read = pBufSz->X * pBufSz->Y * sizeof(CHAR_INFO) + VTNT_MIN_READ;
                    debug(F111,"VTNT char_info bytes","vtnt_read",vtnt_read);

                    if ( pBufSz->X > pScrnBufInf->dwSize.X )
                        debug(F101,"VTNT WARNING BufSz->X > ScrnBufInf->Size.X","",
                               pBufSz->X);
                    if ( pBufSz->Y > pScrnBufInf->dwSize.Y )
                        debug(F101,"VTNT WARNING BufSz->Y > ScrnBufInf->Size.Y","",
                               pBufSz->Y);

                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO dwSize.X","",pScrnBufInf->dwSize.X);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO dwSize.Y","",pScrnBufInf->dwSize.Y);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO dwCursorPosition.X","",pScrnBufInf->dwCursorPosition.X);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO dwCursorPosition.Y","",pScrnBufInf->dwCursorPosition.Y);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO wAttributes","",pScrnBufInf->wAttributes);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO srWindow.Left","",pScrnBufInf->srWindow.Left);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO srWindow.Top","",pScrnBufInf->srWindow.Top);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO srWindow.Right","",pScrnBufInf->srWindow.Right);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO srWindow.Bottom","",pScrnBufInf->srWindow.Bottom);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO dwMaximumWindowSize.X","",pScrnBufInf->dwMaximumWindowSize.X);
                    debug(F101,"VTNT CONSOLE_SCREEN_BUFFER_INFO dwMaximumWindowSize.Y","",pScrnBufInf->dwMaximumWindowSize.Y);
                    debug(F101,"VTNT CURSOR X","",pCursor->X);
                    debug(F101,"VTNT CURSOR Y","",pCursor->Y);
                    debug(F101,"VTNT BUFFER COORD X","",pBufCoord->X);
                    debug(F101,"VTNT BUFFER COORD Y","",pBufCoord->Y);
                    debug(F101,"VTNT BUFFER SIZE X","",pBufSz->X);
                    debug(F101,"VTNT BUFFER SIZE Y","",pBufSz->Y);
                    debug(F101,"VTNT WRITE REGION Left","",  pWriteRegion->Left);
                    debug(F101,"VTNT WRITE REGION Top","",   pWriteRegion->Top);
                    debug(F101,"VTNT WRITE REGION Right","", pWriteRegion->Right);
                    debug(F101,"VTNT WRITE REGION Bottom","",pWriteRegion->Bottom);

#ifdef COMMENT
                    /* Compare screen dimensions and switch if they do not match */
                    if ( VscrnGetWidth(VTERM) != w_vtnt ) {
                        if ( w_vtnt > 0 && w_vtnt <= MAXTERMROW) {
                            debug(F101,"VTNT Width Changed to","",w_vtnt);
                            VscrnSetWidth(VTERM,w_vtnt);
                            tt_rows[VTERM] = w_vtnt;
#ifndef KUI
                            vt100screen.mi.col = w_vtnt;
#endif /* KUI */
                            szchng = 1;
                        }
                    }
                    if ( VscrnGetHeight(VTERM) != (h_vtnt + (tt_status[VTERM]?1:0)) ) {
                        if ( h_vtnt > 0 && h_vtnt <= MAXTERMCOL) {
                            debug(F101,"VTNT Height Changed to","",h_vtnt);
                            VscrnSetHeight(VTERM,h_vtnt + (tt_status[VTERM]?1:0));
                            tt_cols[VTERM] = h_vtnt;
#ifndef KUI
                            vt100screen.mi.row = h_vtnt + (tt_status[VTERM]?1:0);
#endif /* KUI */
                            szchng = 1;
                        }
                    }
                    if ( szchng )
                        RestoreTermMode();
#endif /* COMMENT */

                    if (vtnt_index == vtnt_read) {
                        /* In other words, the size of the char info is 0 */
                        VscrnSetCurPos(VTERM,
                                        pCursor->X,
                                        pCursor->Y);
                        VscrnIsDirty(VTERM);

                        vtnt_index = 0;
                        vtnt_read = VTNT_MIN_READ;
                        memset(vtnt_buf,0,VTNT_BUFSZ);
                    }
                }
                else if (vtnt_index == vtnt_read) {
                    /* We should now have the complete set of struct data */
                    /* now to process it  */
                    USHORT Row, Col;
                    viocell  vio={0,0};
                    vtattrib vta={0,0,0,0,0,0,0,0,0,0,0,0,0,0};

                    pScrnBufInf = (PCONSOLE_SCREEN_BUFFER_INFO) vtnt_buf;
                    pCursor = (PCOORD) ((PCHAR) pScrnBufInf
                                         + sizeof(CONSOLE_SCREEN_BUFFER_INFO));
                    pBufCoord = (PCOORD) ((PCHAR) pCursor + sizeof(COORD));
                    pBufSz = (PCOORD) ((PCHAR) pBufCoord + sizeof(COORD));
                    pWriteRegion = (PSMALL_RECT) ((PCHAR) pBufSz
                                                   + sizeof(COORD));
                    pCharInfo = (PCHAR_INFO) ((PCHAR) pWriteRegion
                                               + sizeof(SMALL_RECT));

                    ckhexdump("VTNT CharInfo",pCharInfo,vtnt_read-VTNT_MIN_READ);

                    Row = pWriteRegion->Top;
                    Col = pWriteRegion->Left;
                    while ( (PCHAR) pCharInfo < &vtnt_buf[vtnt_index] &&
                            (Row < pWriteRegion->Bottom ||
                            Row == pWriteRegion->Bottom &&
                              Col <= pWriteRegion->Right)) {
                        if ( ck_isunicode() )
                        {
                            vio.c = pCharInfo->Char.UnicodeChar;
                        }
                        else {
                            if (GNOW->itol)
                                vio.c = (*GNOW->itol)(pCharInfo->Char.UnicodeChar);
                            else
                                vio.c = (pCharInfo->Char.UnicodeChar & 0xFF);
                        }
                        vio.video_attr = cell_video_attr_from_vio_attribute(pCharInfo->Attributes & 0xFF);
                        VscrnWrtCell(VTERM,
                                      vio,
                                      vta,
                                      Row,
                                      Col);
                        if ( ++Col > pWriteRegion->Right ) {
                            Row++;
                            Col = pWriteRegion->Left;
                        }
                        pCharInfo++;
                    }
                    VscrnSetCurPos(VTERM,
                                    pCursor->X,
                                    pCursor->Y);
                    VscrnIsDirty(VTERM);

                    vtnt_index = 0;
                    vtnt_read = VTNT_MIN_READ;
                    memset(vtnt_buf,0,VTNT_BUFSZ);
                }
            }
        }
        return;
    }

    /* The VT100 and up output a SUB character *in addition to* acting on it
     * to cancel any escape sequence in progress */
    if (ch == SUB && ISVT100(tt_type_mode)) {
        if (ISVT220(tt_type_mode)) {
            wrtch(0x2426);    /* Unicode backwards questionmark for VT220+*/
        }
        else {
            wrtch(0x2592);    /* Unicode half-tone block for VT100*/
        }
    }

/*
  Even if debugging, we still plow through the escape-sequence state table
  switcher, but we don't call any of the action routines.
  This lets us highlight text that appears inside an escape sequence.
*/

    if (escstate == ES_NORMAL) {        /* Not in an escape sequence */
        if (ch == ESC &&
             !literal_ch) {             /* This character is an Escape */
            escstate = ES_GOTESC;       /* Change state to GOTESC */
            esclast = 0;                /* Reset buffer pointer */
            escbuffer[0] = ESC;
        }
        else if ( ch == _CSI && !literal_ch) {
            escstate = ES_GOTCSI;       /* Escape sequence was restarted */
            escbuffer[0] = _CSI;         /* Save in case we have to replay it */
            esclast = 1;                /* Reset buffer pointer, but */
            escbuffer[1] = '[';         /* But translate for vtescape() */
        } else {                        /* Not an ESC, stay in NORMAL state */
          if (!debses)
            vt100(ch);          /* and send to vt100() for display. */
        }
        return;                 /* Return in either case. */
    }

/* We are in an escape sequence... */

    if (ch < SP || (ch == _CSI)) {                 /* Control character? */
        if ( xprint ) {                            /* During a transparent print the */
            int i;                                 /* only sequence we care about is */
            if ( !debses && escstate != ES_NORMAL ) { /* CSI 4 i.                    */
                switch ( escbuffer[0] ) {
                case ESC:
                    i = 0;                         /* ESC is beginning of C0 sequence */
                    break;
                case _CSI:
                    prtchar(_CSI);                    /* We really had a C1 sequence */
                    i = 2;
                    break;
                default:
                    prtchar(ESC);                    /* it must have been C0, and we made */
                    i = 1;                         /* a coding mistake */
                }
                for ( ; i <= esclast; i++ )        /* Print what we've got. */
                    prtchar(escbuffer[i]);
            }
            esclast  = 0;               /* Reset the buffer */
            escbuffer[0] = 0;           /* And clear the first char, just in case */
            escstate = ES_NORMAL;       /* Go back to normal */
            cwrite(ch);                 /* And then restart */
        } else if ( escstate == ES_GOTESC && ISANSI(tt_type_mode) && crm ) {
            if ( !debses )
                vt100(ch);
            escstate = ES_NORMAL;       /* Go back to normal */
        } else if (ch == CAN || ch == SUB) { /* These cancel an escape sequence  */
            /* According to the 97801-5xx manual.  SUB is different from CAN in  */
            /* that SUB outputs to the screen the characters received as part of */
            /* the escape sequence. However, the only noticeable difference on   */
            /* the VT320 is that a backwards question mark is printed whenever a */
            /* SUB is received.                                                  */

            if (dcsrecv) {
                process_canceled_decdld();
            }
            escstate = ES_NORMAL;            /* Go back to normal. */
#ifdef CK_APC
            apclength = 0;
            apcbuf[0] = 0 ;
            apcactive = APC_INACTIVE ;
            apcrecv = FALSE ;
            dcsrecv = FALSE ;
            pmrecv  = FALSE ;
            oscrecv = FALSE ;
            oscterm = 0;
            pu1recv = FALSE ;
            pu2recv = FALSE ;
            c1strrecv = FALSE ;
#endif /* CK_APC */
        } else if (ch == BS) {  /* Erases previous */
            if ( escstate == ES_GOTCSI && esclast == 1 ) {
                escstate = ES_GOTESC ;
                esclast = 0 ;
            }
            else if ( escstate == ES_ESCSEQ && esclast == 1 ) {
                escstate = ES_GOTESC ;
                esclast = 0 ;
            }
            else if ( escstate == ES_GOTESC && esclast == 0 ) {
                escstate = ES_NORMAL ;
            }
            else if ( escstate == ES_TERMIN ) {
                escstate = ES_STRING ;
            }
            else if ( escstate == ES_STRING ) {
#ifdef CK_APC
                if ( apclength > 0) {
					/* The VT520 doesn't seem to act on a BS appearing in a
					 * macro definition (DECDMAC) */
					if (!(dcsrecv && ISVT420(tt_type_mode)))
                    	apclength-- ;
				}
                else
#endif /* CK_APC */
                {
                    escstate = ES_GOTESC ;
                }
            }
            else if ( esclast > 0 ) {
                esclast--;              /* escape sequence char (really?) */
            }
        } else if (ch == ESC) {
            if ( escstate == ES_STRING )
                escstate = ES_TERMIN ;
            else {
                escstate = ES_GOTESC;   /* Escape sequence was restarted */
                esclast = 0;            /* Reset buffer pointer */
                escbuffer[0] = ESC;     /* Save in case we have to replay it */
            }
        } else if (ch == _CSI) {
            escstate = ES_GOTCSI;       /* Escape sequence was restarted */
            escbuffer[0] = _CSI;         /* Save in case we have to replay it */
            esclast = 1;                /* Reset buffer pointer, but */
            escbuffer[1] = '[';         /* But translate for vtescape() */
        }

        if (!(ch == BEL && oscrecv)) {
            /* Only return here on BEL if we're not receiving an OSC string
             * as that signals end of string. If BEL is in fact not the string
             * terminator then that could be a problem but not as big a problem
             * as if it is and we miss it. */

			/* If we're absorbing a DCS string, just discard control characters
               - this appears to be what the VT520 does */
            if (ch != NUL && !(escstate == ES_STRING && dcsrecv)) {
                wrtch(ch);
            }
            return;
        }
    }
/*
  Put this character in the escape sequence buffer.
  But we don't put "strings" in this buffer; either absorb them silently
  (as with Operating System Command), or handle them specially (as with APC).
  Note that indexing starts at 1, not 0.
*/
    if ( escstate != ES_STRING && escstate != ES_TERMIN )
        if (esclast < ESCBUFLEN)
            escbuffer[++esclast] = ch;


   /* Note: vtescape() sets escstate back to ES_NORMAL. */

   if (ISVT52(tt_type_mode)) {          /* VT52 Emulation */
      switch (esclast) {
      case 1:                           /* First char after Esc */
          switch ( ch ) {
          case 'Y':
              vt52esclen = 3 ;
              break;
          case 'r':
          case 'x':
          case 'y':
              vt52esclen = 2 ;
              break;
          default:
              vtescape() ;
          }
          break;
      default:
          if ( esclast == vt52esclen )
              vtescape() ;              /* then it's a complete sequence */
          else if ( esclast > vt52esclen )
              escstate = ES_NORMAL;     /* Something unexpected, ignore */
          break;
      }
       return;                                /* Done with VT52 */
   }

   /* The rest of this routine handles ANSI/VT1xx/VT2xx/VT3xx/VT4xx/VT5xx emulation... */

    switch (escstate) {                 /* Enter esc sequence state switcher */
    case ES_GOTESC:                     /* GOTESC state, prev char was Esc */
        switch ( ch ) {
        case '[':                       /* Left bracket after ESC is CSI */
            escstate = ES_GOTCSI;       /* Change to GOTCSI state */
            break;
        case '_':                       /* Application Program Command (APC) */
            if ( !xprint ) {
                escstate = ES_STRING;   /* Enter STRING-absorption state */
                if ( !savefiletext[0] )
                    ckstrncpy(savefiletext,filetext,sizeof(savefiletext));
                ckstrncpy(filetext,"APC STRING",sizeof(filetext)) ;
                VscrnIsDirty(VTERM);    /* Update status line */
#ifdef CK_APC
                apcrecv = TRUE;         /* We are receiving an APC string */
                apclength = 0;          /* and reset APC buffer pointer */
#endif /* CK_APC */
            } else {
                vtescape();                               /* Go act on it. */
            }
        case 'P':                       /* Device Control String (DCS) Introducer */
            if ( !xprint) {
                escstate = ES_STRING;   /* Enter STRING-absorption state */
#ifdef CK_APC
                dcsrecv = TRUE ;        /* Set DCS-Active flag */
                apclength = 0 ;         /* we use the same buffer as for APC */
#endif /* CK_APC */
                if ( !savefiletext[0] )
                    ckstrncpy(savefiletext,filetext,sizeof(savefiletext));
                ckstrncpy(filetext,"DCS STRING",sizeof(filetext)) ;
                VscrnIsDirty(VTERM);    /* Update status line */
            } else {
                vtescape();                               /* Go act on it. */
            }
            break;
        case 'Q':                       /* Private Use One (PU1) Introducer 97801-5xx */
            if ( !xprint && !ISANSI(tt_type_mode) &&
                    (!ISVT220(tt_type_mode) || ISK95(tt_type_mode)) ) {
                /* 
                 * SCOANSI used ESC Q to prefix keyboard assignments
                 * so do not enter the string state.
                 *
                 * And VT220/420/520 don't do anything with PU1 either - they
                 * just write the string to the screen. Probably this applies
                 * to the VT10x too, but I don't have one of those to test
                 * against to know for sure.
                 */
                escstate = ES_STRING;   /* Enter STRING-absorption state */
#ifdef CK_APC
                pu1recv = TRUE ;        /* Set PU1-Active flag */
                apclength = 0 ;         /* we use the same buffer as for APC */
#endif /* CK_APC */
                if ( !savefiletext[0] )
                    ckstrncpy(savefiletext,filetext,sizeof(savefiletext));
                ckstrncpy(filetext,"PU1 STRING",sizeof(filetext)) ;
                VscrnIsDirty(VTERM);    /* Update status line */
            }
            else {
                vtescape();                               /* Go act on it. */
            }
            break;
        case 'R':                       /* Private Use Two (PU2) Introducer 97801-5xx */
            if ( !xprint && (!ISVT220(tt_type_mode) || ISK95(tt_type_mode))) {
                /* VT220/420/520 don't do anything with PU2 - they just write
                 * the string to the screen. Probably this applies
                 * to the VT10x too, but I don't have one of those to test
                 * against to know for sure. */
                escstate = ES_STRING;   /* Enter STRING-absorption state */
#ifdef CK_APC
                pu2recv = TRUE ;        /* Set PU2-Active flag */
                apclength = 0 ;         /* we use the same buffer as for APC */
#endif /* CK_APC */
                if ( !savefiletext[0] )
                    ckstrncpy(savefiletext,filetext,sizeof(savefiletext));
                ckstrncpy(filetext,"PU2 STRING",sizeof(filetext)) ;
                VscrnIsDirty(VTERM);    /* Update status line */
            }
            else {
                vtescape();                               /* Go act on it. */
            }
            break;
        case 'X':                       /* Start-Of-String (SOS) Ignored */
            if ( !xprint ) {
                escstate = ES_STRING;   /* Enter STRING-absorption state */
#ifdef CK_APC
                c1strrecv = TRUE ;      /* Set Active flag */
                apclength = 0 ;         /* we use the same buffer as for APC */
#endif /* CK_APC */
                if ( !savefiletext[0] )
                    ckstrncpy(savefiletext,filetext,sizeof(savefiletext));
                ckstrncpy(filetext,"SOS STRING",sizeof(filetext));
                VscrnIsDirty(VTERM);    /* Update status line */
            }
            else {
                vtescape();             /* Go act on it. */
            }
            break;
        case 'Z':                       /* DECID */
            if ( ISVT52(tt_type_mode) ) {
                sendescseq(tt_info[TT_VT52].x_id);
            }
            else if ( ISVT220(tt_type) ) {
                sendescseq(tt_info[tt_type].x_id);
            }
            break;
        case '^':                       /* Privacy Message (PM) */
            if ( !xprint ) {
                escstate = ES_STRING;   /* Enter STRING-absorption state */
#ifdef CK_APC
                pmrecv = TRUE ;       /* Set PM-Active flag */
                apclength = 0 ;         /* we use the same buffer as for APC */
#endif /* CK_APC */
                if ( !savefiletext[0] )
                    ckstrncpy(savefiletext,filetext,sizeof(savefiletext));
                ckstrncpy(filetext,"PM STRING",sizeof(filetext)) ;
                VscrnIsDirty(VTERM);    /* Update status line */
                break;
            }
        case ']':                       /* Operating System Command (OSC) */
            if ( !xprint ) {
                escstate = ES_STRING;   /* Enter STRING-absorption state */
#ifdef CK_APC
                oscrecv = TRUE ;      /* Set OSC-Active flag */
                apclength = 0 ;         /* we use the same buffer as for APC */
#endif /* CK_APC */
                if ( !savefiletext[0] )
                    ckstrncpy(savefiletext,filetext,sizeof(savefiletext));
                ckstrncpy(filetext,"OSC STRING",sizeof(filetext)) ;
                VscrnIsDirty(VTERM);    /* Update status line */
                break;
            }
        default:
            if ((ch > 057) && (ch < 0177)) /* Or final char, '0' thru '~' */
                vtescape();                               /* Go act on it. */
            else
                escstate = ES_ESCSEQ;
         }
         break;

    case ES_ESCSEQ:                     /* ESCSEQ -- in an escape sequence */
        if (ch > 057 && ch < 0177)      /* Final character is '0' thru '~' */
          vtescape();                   /* Go handle it */
        break;

    case ES_GOTCSI:                     /* GOTCSI -- In a control sequence */
        if (ch > 077 && ch < 0177)      /* Final character is '@' thru '~' */
          vtescape();                   /* Go act on it. */
        break;

    case ES_STRING:                     /* Inside a string */
        if (ch == ESC)                  /* ESC may be 1st char of terminator */
          escstate = ES_TERMIN;         /* Change state to find out. */
        else if (ISLINUX(tt_type_mode) && oscrecv && apclength == 0
            && (ch == 'R' || ch == 'P')) {
            /* Linux console palette escape sequences start with an OSC but
             * aren't terminated at all. If we let them be handled by the
             * normal OSC processing code it may cause the terminal to appear
             * to hang.
             * ESC ] R           Reset Palette
             * ESC ] P nrrggbb   Set  Palette
             *
             * From the man page console_codes(4), bugs section:
             * Linux "private mode" sequences do not follow the rules in ECMA-48
             * for private mode control sequences.  In particular, those ending
             * with ] do not use a standard terminating character.  The OSC (set
             * palette) sequence is a greater problem, since xterm(1) may
             * interpret this as a control sequence which requires a string
             * terminator (ST).  Unlike the setterm(1) sequences which will be
             * ignored (since they are invalid control sequences), the palette
             * sequence will make xterm(1) appear to hang (though pressing the
             * return-key will fix that).  To accommodate applications which
             * have been hardcoded to use Linux control sequences, set the
             * xterm(1) resource brokenLinuxOSC to true.
             *
             */
            if (ch == 'R') {
                /* Reset Palette */
                debug(F100, "Bad linux OSC - reset palette", "", 0);

                reset_palettes();

                escstate = ES_NORMAL;
                oscrecv = FALSE;
                oscterm = 0;
            } else {
                /* We need to absorb 7 characters */
                escstate = ES_BADLINUXOSC;
            }
        }
#ifdef CK_APC
        else if ( ch == BEL /*&& ISAIXTERM(tt_type_mode)*/ && oscrecv ) {
            /* BEL terminates an OSC string in AIXTERM
             *
             * DavidG 2022-07-21 - And also in the windows 10 console (ConPTY)
             *   K-95 used to only do this for AIXTERM but the result if an
             *   unexpected BEL string terminator is missed is pretty bad - data
             *   is accumulated into apcbuf forever and the user sees no
             *   output.
             *
             *   So while it is non-standard K-95 will now always accept
             *   BEL as a string terminator. This is also what XTerm does:
             *      https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
             * */
            oscterm = BEL;
            escstate = ES_NORMAL;       /* If so, back to NORMAL */
            if (savefiletext[0]) {              /* Fix status line */
                ckstrncpy(filetext,savefiletext,sizeof(filetext));
                savefiletext[0] = NUL;
                VscrnIsDirty(VTERM);  /* status line needs to be updated */
            }
            apcbuf[apclength] = NUL; /* terminate it */
                                       /* process it */
            if (!debses)
                doosc() ;
            oscrecv = FALSE ;
            oscterm = 0;
        }
        else if (apcrecv || dcsrecv || oscrecv || pmrecv ||
                  pu1recv || pu2recv || c1strrecv) {
            if (apclength < apcbuflen)    /* If in APC string, */
              apcbuf[apclength++] = ch;   /* deposit this character */
            else {                        /* Buffer overrun */
                apcrecv = FALSE ;         /* Discard what we got */
                dcsrecv = FALSE ;
                oscrecv = FALSE ;
                oscterm = 0;
                pmrecv  = FALSE ;
                pu1recv = FALSE ;
                pu2recv = FALSE ;
                c1strrecv = FALSE ;
                apclength = 0;            /* and go back to normal */
                apcbuf[0] = 0;            /* Not pretty, but what else */
                escstate = ES_NORMAL ;
            }
        }
#endif /* CK_APC */
        break;                          /* Absorb all other characters. */

    case ES_BADLINUXOSC:
        /*
         * Handle the linux ESC ] P nrrggbb sequence to set the Palette
         */
        if (apclength < 7) {
            apcbuf[apclength++] = ch;
        }

        if (apclength >= 7) {
#ifdef KUI
            int index, r, g, b;
            int color;
            ULONG *palette = NULL;
#endif /* KUI */

            /* Set Palette */
            apcbuf[apclength++] = 0;
            debug(F110, "Bad linux OSC - set palette", apcbuf, 0);

#ifdef KUI
            if (sscanf(apcbuf, "%1x%2x%2x%2x", &index, &r, &g, &b)) {
                debug(F110, "Bad linux OSC - set palette", "index", index);
                debug(F110, "Bad linux OSC - set palette", "r", r);
                debug(F110, "Bad linux OSC - set palette", "g", g);
                debug(F110, "Bad linux OSC - set palette", "b", b);
                if (index <= 15) {
                    color = (unsigned)(((unsigned)b << 16) |
                            (unsigned)((unsigned)g << 8) |
                            (unsigned)r);
                    palette = current_palette_rgb_table();
                    index = color_index_to_vio(index);
                    palette[index] = color;
                }
            }
#endif

            escstate = ES_NORMAL;
            oscrecv = FALSE;
            oscterm = 0;
            apclength = 0;
            apcbuf[0] = 0;
        }

        break;

    case ES_TERMIN:                     /* May have a string terminator */
        if (ch == '\\') {               /* which must be backslash */
            escstate = ES_NORMAL;       /* If so, back to NORMAL */
            if (savefiletext[0]) {              /* Fix status line */
                ckstrncpy(filetext,savefiletext,sizeof(filetext));
                savefiletext[0] = NUL;
                VscrnIsDirty(VTERM);  /* status line needs to be updated */
            }
#ifdef CK_APC
            if (apcrecv && apclength > 0)/* If it was an APC string, */
            {
                apcbuf[apclength] = NUL; /* terminate it */
                if ((apcstatus & APC_ON) && !debses) {
                    apc_command(APC_REMOTE,apcbuf);
                    return;             /* with the apcactive flag still set */
                }
                else apcactive = APC_INACTIVE;
            }
            else if ( dcsrecv ) /* it was a DCS string, */
            {
                apcbuf[apclength] = NUL; /* terminate it */

                if ( tt_type_mode >= TT_VT220 && /* and if we are a VT320 */
                     tt_type_mode <= TT_WY370 || /* Or K95 or xterm */
                     ISK95(tt_type_mode) || ISXTERM(tt_type_mode))
                {                            /* process it */
                    if (!debses)
                      dodcs() ;
                }
                dcsrecv = FALSE ;
            }
            else if ( pu1recv ) /* it was a PU1 string, */
            {
                apcbuf[apclength] = NUL; /* terminate it */
                if ( IS97801(tt_type_mode) )
                {                            /* process it */
                    if (!debses)
                      dopu1() ;
                }
                pu1recv = FALSE ;
            }
            else if ( pu2recv ) /* it was a PU2 string, */
            {
                apcbuf[apclength] = NUL; /* terminate it */
                if ( IS97801(tt_type_mode) )
                {                            /* process it */
                    if (!debses)
                      dopu2() ;
                }
                pu2recv = FALSE ;
            }
            else if ( oscrecv ) /* it was a OSC string, */
            {
                apcbuf[apclength] = NUL; /* terminate it */
                if ( tt_type_mode >= TT_VT320 && /* and if we are a VT320 */
                     tt_type_mode <= TT_WY370 )
                {                            /* process it */
                    if (!debses)
                      doosc() ;
                }
                oscrecv = FALSE ;
                oscterm = 0;
            }
#endif /* CK_APC */
        } else if (ch == '@' && dcsrecv &&
            (tt_type == TT_VT220 || tt_type == TT_VT220PC) ) {
            /* VT220 ignores a PAD character in the DCS string - at least for
             * DECDLD */
            escstate = ES_STRING;
        } else {
#ifdef CK_APC
            if ( dcsrecv ) {
                process_canceled_decdld();

                dcsrecv = FALSE ;
                apcbuf[0] = NUL ;
                apclength = 0 ;
                escstate = ES_GOTESC ;
                if (savefiletext[0]) {          /* Fix status line */
                    ckstrncpy(filetext,savefiletext,sizeof(filetext));
                    savefiletext[0] = NUL;
                    VscrnIsDirty(VTERM);  /* status line needs to be updated */
                }
                cwrite(ch);
            }
            else {
#endif /* CK_APC */
                if ( ch >= SP )         /* Just a stray Esc character. */
                    escstate = ES_STRING;       /* Return to string absorption. */
#ifdef CK_APC
                if (apcrecv) {
                    if (apclength+1 < apcbuflen) { /* In APC string, */
                        apcbuf[apclength++] = ESC;   /* deposit the Esc character */
                        apcbuf[apclength++] = ch;    /* and this character too */
                    }
                }
            }
#endif /* CK_APC */
        }
    }
#endif /* NOTERM */
}

/*---------------------------------------------------------------------------*/
/* scrninit                                                                  */
/*---------------------------------------------------------------------------*/
void
scrninit() {
    if (deccolm)
      Set132Cols(VTERM) ;
    else
      SetCols(VTERM) ;

    naws();

    setborder();
    VscrnIsDirty(VTERM);
}

/*---------------------------------------------------------------------------*/
/* wrtch                                                                     */
/*---------------------------------------------------------------------------*/
void
wrtch(unsigned short ch) {
    viocell cell;
    vtattrib vta = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    int vmode = decsasd == SASD_TERMINAL ? VTERM : VSTATUS ;
    extern int k95stdio,k95stdin,k95stdout;

    if (printon && xprint && !debses)   /* If transparent print active, */
      return;                           /*  we don't touch the screen. */

    if ( !IsConnectMode() && !interm )
        return;                         /* Don't touch screen if being */
                                        /* executed from an input cmd  */

    if ( k95stdout ) {
#ifdef putchar
#undef putchar
#endif
        putchar(ch);
        return;
    }

    prevchar = ch;                      /* save char for Repeat operations */

    if (ch >= SP || literal_ch || crm ||
         ((ISWYSE(tt_type_mode) || ISTVI(tt_type_mode)) &&
           (ch == STX || ch == ETX)))
    {                                   /* Treat as a Normal character */
        if (attrib.invisible)
          ch = SP;

        if ( ck_isunicode() && crm && ch < SP ) {
            if ( ISANSI(tt_type_mode) )
                ch = (*xl_u[TX_IBMC0GRPH])(ch) ;
            else
                ch = (*xl_u[TX_C0PICT])(ch) ;
        }
        if ( (!tt_hidattr || ISHP(tt_type_mode)) &&
             (attrmode == ATTR_PAGE_MODE || attrmode == ATTR_LINE_MODE) )
        {
            /* Read the current attribute for wherex,wherey and */
            /* use it for the current location                  */
            vta = VscrnGetVtCharAttr( vmode,
                                      wherex[vmode]-1,
                                      wherey[vmode]-1 ) ;
            if ( !tt_hidattr )
                vta.wyseattr = FALSE ;
            cell.c = ch;
            cell.video_attr = attribute;
            vta.erased = FALSE;

            if ( (ISWYSE(tt_type_mode) ||
                   ISTVI(tt_type_mode) ||
                   ISHZL(tt_type_mode) )
                 && protect ) {
                /* If the current cursor is on a protected cell */
                /* then we must advance the cursor to the first */
                /* non-protected cell on the screen             */
                int x = wherex[vmode];
                int y = wherey[vmode];
                int width = VscrnGetWidth(vmode);

                while ( vta.unerasable ) {
                    if ( !vta.unerasable ) /* bug in MSVC 5.0 */
                        break;
                    x++;
                    if ( x > width ) {
                        y++;
                        if ( y >= vscrn_c_page_margin_bot(VTERM) ) {
                            x-- ;
                            y-- ;
                            return ;    /* Can't write this character */
                        }
                        x = 1 ;
                    }

                    lgotoxy(vmode,x,y); /* set wherex, wherey */

                    /* Retrieve the attributes of the new position */
                    vta = VscrnGetVtCharAttr( vmode,x-1,y-1 ) ;
                    vta.erased = FALSE;
                    if ( !tt_hidattr )
                        vta.wyseattr = FALSE ;
                }
            }

            if (insertmode) {
                VscrnScrollRt(vmode,
                               wherey[vmode] - 1,
                               wherex[vmode] - 1,
                               wherey[vmode] - 1,
                               VscrnGetWidth(vmode) - 1,
                               1, cell);
                /* VscrnScrollRt() doesn't apply the current attribute */
                VscrnWrtCell(vmode, cell, vta,
                          wherey[vmode] - 1,
                              wherex[vmode] - 1);
                if ( vta.wyseattr ) {
                    /* the attribute is only assigned at one place */
                    vta.wyseattr = FALSE;
                    VscrnWrtCell(vmode, cell, vta,
                                  wherey[vmode] - 1,
                                  wherex[vmode]);
                }
            }
            else {
                vta.unerasable = attrib.unerasable ;    /* use current write protect */

                VscrnWrtCell(vmode, cell, vta,
                          wherey[vmode] - 1,
                              wherex[vmode] - 1);
            }

            literal_ch = FALSE;
            /* don't wrap if autowrap is off */
            if ( tt_wrap || wherex[vmode] < VscrnGetWidth(vmode) ) {
                if (++wherex[vmode] > VscrnGetWidth(vmode)) {
                    if ( autoscroll && !protect || wherey[vmode] < vscrn_c_page_margin_bot(VTERM) ) {
                        wherex[vmode] = 1;
                        wrtch((char) LF);
                    }
                }
            }
        }
        else    /* We are in character attribute mode */
        {
            int rmargin = cursor_right_margin(vmode);
            cell.c = ch;
            cell.video_attr = attribute;

            if ( (ISWYSE(tt_type_mode) ||
                   ISTVI(tt_type_mode) ||
                   ISHZL(tt_type_mode) )
                 && protect ) {
                int width = VscrnGetWidth(vmode);
                /* If the current cursor is on a protected cell */
                /* then we must advance the cursor to the first */
                /* non-protected cell on the screen             */

                vta = VscrnGetVtCharAttr( vmode,
                                          wherex[vmode]-1,
                                          wherey[vmode]-1 ) ;

                while ( vta.unerasable ) {
                    if ( !vta.unerasable )  /* MSVC 5.0 bug */
                        break;
                    if ( ++wherex[vmode] > width ) {
                        if ( ++wherey[vmode] >= vscrn_c_page_margin_bot(vmode) ) {
                            wherex[vmode]-- ;
                            wherey[vmode]-- ;
                            return ;    /* Can't write this character */
                        }
                        wherex[vmode] = 1 ;
                    }

                    lgotoxy(vmode,wherex[vmode],wherey[vmode]);
                }
            }

            if (insertmode) {
                VscrnScrollRt(vmode, wherey[vmode] - 1,
                               wherex[vmode] - 1, wherey[vmode] - 1,
                               VscrnGetWidth(vmode) - 1, 1, cell);
                /* VscrnScrollRt() doesn't apply the current attribute */
                VscrnWrtCell(vmode, cell, attrib,
                          wherey[vmode] - 1,
                              wherex[vmode] - 1);
            }
            else {
                VscrnWrtCell(vmode, cell, attrib,
                          wherey[vmode] - 1, wherex[vmode] - 1);
            }

            literal_ch = FALSE;
            /* don't wrap if autowrap is off */
            if (tt_wrap || wherex[vmode] < rmargin ) {
                if (++wherex[vmode] > rmargin && decsasd == SASD_TERMINAL) {
                    if ( IS97801(tt_type_mode) ) {
                        if ( !sni_pagemode ) {
                            wherex[vmode] = 1;
                            wrtch((char) LF);
                        }
                        else {  /* Page Mode */
                            lgotoxy(VTERM,1,vscrn_c_page_margin_top(vmode));
                        }

                    }
                    else if ( autoscroll && !protect || wherey[vmode] < vscrn_c_page_margin_bot(VTERM) ) {
                        wherex[vmode] = cursor_left_margin(vmode);
                        wrtch((char) LF);
                    }
                }
            }
        }

    }
    else
    {   /* Control character */
        
        switch (ch) {
        case LF:
          dolf:
            if ( printon && is_aprint() ) {
                prtline( wherey[VTERM], LF ) ;
            }
            if ( decsasd == SASD_TERMINAL ) {
#ifdef KUI
                /* If a smooth scroll is in progress, a line feed anywhere is
                 * blocked until the scroll is finished. If we don't do this,
                 * then you'll see the prompt in GNU Less jump up a little every
                 * time you scroll up. The VT100 Technical Manual (EK-VT100-TM)
                 * also says "When a line feed is received the microprocessor
                 * waits for the current scroll to end" (pg 4-96) so this is
                 * probably the correct place for the wait. */
                if (scrollmode >= TTS_SMOOTH && vmode == VTERM) {
                    if (in_smooth_scroll) {
                        WaitSmoothScrollFinishedSem(5000);
                    } else if (in_bg_smooth_scroll) {
                        /* Smooth scrolling on a background page just introduces
                         * a delay. There is nothing to render, so we just
                         * pause for the length of time the renderer *would*
                         * have spent scrolling the line */
                        DWORD time = timeGetTime();
                        int sleep_time = bg_smooth_scroll_ends - time;
                        if (sleep_time > 0) {
                            msleep(sleep_time);
                        }
                        in_bg_smooth_scroll = FALSE;
                    }
                }
#endif /* KUI */

                if (wherey[vmode] == vscrn_c_page_margin_bot(VTERM)) {
                    if ( IS97801(tt_type_mode) ) {
                        if ( !sni_pagemode )
                            VscrnScroll(vmode,UPWARD, vscrn_c_page_margin_top(VTERM) - 1, vscrn_c_page_margin_bot(VTERM) - 1, 1,
                                         (vscrn_c_page_margin_top(VTERM) == 1), SP, FALSE ) ;
                        else /* Page Mode */
                            wherex[VTERM] = 1;
                    } else if ( autoscroll && !protect ) {
                        int x = wherex[VTERM];
                        int lmargin = vscrn_c_page_margin_left(VTERM);
                        int rmargin = vscrn_c_page_margin_right(VTERM);
                        if (lmargin <= x && x <= rmargin) {
                            VscrnScrollPage(
                                vmode,
                                UPWARD,
                                vscrn_c_page_margin_top(VTERM) - 1,
                                vscrn_c_page_margin_bot(VTERM) - 1,
                                vscrn_c_page_margin_left(VTERM) - 1,
                                vscrn_c_page_margin_right(VTERM) - 1,
                                1,
                                vscrn_c_page_margin_top(VTERM) == 1,
                                SP,
                                vscrn_current_page_number(vmode, FALSE) ) ;
                        }
                    } else if ( wherex[vmode] > VscrnGetWidth(vmode) )
                        wherex[vmode] = VscrnGetWidth(vmode);
                } else {
                    wherey[vmode]++;
                    if (wherey[vmode] >= VscrnGetHeight(vmode)+(tt_status[VTERM]?0:1)) {
                        if ( IS97801(tt_type_mode) ) {
                            if (wherey[vmode] == VscrnGetHeight(vmode)+(tt_status[VTERM]?0:1)
                                 && decssdt == SSDT_HOST_WRITABLE)
                                setdecsasd(SASD_STATUS);
                            wherey[vmode] = vscrn_c_page_margin_top(VTERM);
                        } else
                            wherey[vmode] = VscrnGetHeight(vmode)+(tt_status[VTERM]?0:1)-1;
                    }
                }
            }
            break;
        case CK_CR:
            if ( (IS97801(tt_type_mode) || ISHP(tt_type_mode)) &&
                 vmode == VTERM )
                wherex[vmode] = cursor_left_margin(vmode);
            else
                wherex[vmode] = cursor_left_margin(vmode);
            if ( !(ISANSI(tt_type_mode) || ISHFT(tt_type_mode)) )
                wrapit = FALSE;
            break;
        case BS:
            if ( (IS97801(tt_type_mode) || ISHP(tt_type_mode)) &&
                 vmode == VTERM ) {
                if (wherex[vmode] > vscrn_c_page_margin_left(vmode))
                    wherex[vmode]--;
            }
            else if ( ISQNX(tt_type_mode) && vmode == VTERM ) {
                if ( wherex[vmode] > 1 )
                    wherex[vmode]--;
                else {
                    wherex[vmode] = VscrnGetWidth(vmode);
                    if ( wherey[vmode] > 1 ) {
                        wherey[vmode]--;
                    }
                    else {
                        wherey[vmode] = VscrnGetHeight(vmode)
                            -(tt_status[VTERM]?1:0) ;
                    }
                }
            }
            else {
                if (wherex[vmode] > cursor_pos_left_margin(vmode, wherey[vmode], wherex[vmode]))
                    wherex[vmode]--;
            }
            if ( !(ISANSI(tt_type_mode) || ISHFT(tt_type_mode)) )
                wrapit = FALSE;
            break;
        case FF:
            if ( printon && is_aprint() ) {
                prtline( wherey[VTERM], LF ) ;
            }
            if ( ISSUN(tt_type_mode) && vmode == VTERM) {
                clrscreen(VTERM,SP);
                lgotoxy(VTERM,1,1);       /* and home the cursor */
            } 
            else if ( (IS97801(tt_type_mode) || ISHP(tt_type_mode)) &&
                 vmode == VTERM ) {
                if (wherex[vmode] < vscrn_c_page_margin_right(vmode))
                    wherex[vmode]++;
            }
            else {
                goto dolf;
            }
            break;
        case BEL:
            bleep(BP_BEL);
            break;
        case NUL:                       /* represent it as a space */
            wrtch(SP);
            break;
        case VT:
            if ( printon && is_aprint() ) {
                prtline( wherey[VTERM], LF ) ;
            }
            if ( ISWYSE(tt_type_mode) ||
                 ISTVI(tt_type_mode) ||
                 ISHZL(tt_type_mode) ) 
            {
                if ( wherey[vmode] == vscrn_c_page_margin_top(VTERM) ) {
                    if ( autoscroll && !protect )
                        VscrnScroll(vmode,DOWNWARD, vscrn_c_page_margin_top(VTERM) - 1, vscrn_c_page_margin_bot(VTERM) - 1, 1,
                                     FALSE, SP, FALSE ) ;
                } else {
                    cursorup(0);
                }
            } else if ( ISVT100(tt_type_mode) ) {
                goto dolf;
            }
            break;
        case XFS:
            if ( IS97801(tt_type_mode) ) {
                /* Abbreviated Cursor Position */
                /* <FS> <line + 0x20> <col + 0x20>, 0-based */
                debug(F110,"wrtch - 97801","Abbreviated Cursor Position - not implemented",0);
            }
            break;
        default:;                       /* Ignore */
        }
    }

    if (ch == LF && (tt_type == TT_VT100 || tt_type == TT_VT102)) {
        /* LF does not reset the LCF on a real VT100. The VT220 and VT520
         * emulating a VT100 do reset the LCF. */
        bool lcf = wrapit;
        lgotoxy(vmode,wherex[vmode],wherey[vmode]);
        wrapit = lcf;
    } else {
        lgotoxy(vmode,wherex[vmode],wherey[vmode]);
    }

    if (cursor_on_visible_page(vmode)) {
        /* always mark the Terminal as requiring the update.. if the cursor is
         * on the visible page. */
        VscrnIsDirty(VTERM);
    }
}

/*---------------------------------------------------------------------------*/
/* lgotoxy                                                                   */
/*---------------------------------------------------------------------------*/
void
lgotoxy(BYTE vmode, int x, int y) {
    if ( x < 1 ) x = 1;
    if ( y < 1 ) y = 1;

    if ( vmode == VTERM && decsasd == SASD_STATUS )
        vmode = VSTATUS ;

    if ( vmode == VSTATUS )
        y = 1 ;

    if ( vmode == VTERM && marginbell ) {
        position * cur = VscrnGetCurPos(VTERM) ;
        if ( cur->x+1 < marginbellcol && x >= marginbellcol )
            bleep(BP_BEL) ;
    }

    if ( vmode == VTERM &&
                (ISWYSE(tt_type_mode) ||
           ISTVI(tt_type_mode) ||
           ISHZL(tt_type_mode) )
         && protect ) {
        /* If the current cursor is on a protected cell */
        /* then we must advance the cursor to the first */
        /* non-protected cell on the screen             */
        vtattrib vta = VscrnGetVtCharAttr( VTERM, x-1, y-1 ) ;
        int width    = VscrnGetWidth(VTERM);
        while ( vta.unerasable ) {
            if ( !vta.unerasable )      /* bug in MSVC 5.0 */
                break;
            x++;
            if ( x > width ) {
                y++;
                if ( y > vscrn_c_page_margin_bot(VTERM) ) {
                    y=vscrn_c_page_margin_top(VTERM) ;
                }
                x = 1 ;
            }
            /* Retrieve the attributes of the new position */
            vta = VscrnGetVtCharAttr( VTERM, x-1, y-1 ) ;
        }
    }

    wherex[vmode] = x;
    wherey[vmode] = y;

    wrapit = FALSE;

    if ( markmodeflag[vmode] == notmarking )
      VscrnSetCurPosEx( vmode, x - 1, y - 1, TRUE ) ;
#ifdef COMMENT
    debug(F111,"lgotoxy","vmode",vmode);
    debug(F111,"lgotoxy","x",x);
    debug(F111,"lgotoxy","y",y);
#endif /* COMMENT */

}

/*---------------------------------------------------------------------------*/
/* set_page_margins                                                          */
/*---------------------------------------------------------------------------*/
void
set_page_margins(int page, int topmargin, int bottommargin,
				 int leftmargin, int rightmargin) {
 	vscrn_set_page_margin_top(VTERM,page,topmargin);
 	vscrn_set_page_margin_bot(VTERM,page,bottommargin);
 	vscrn_set_page_margin_left(VTERM,page,leftmargin);
 	vscrn_set_page_margin_right(VTERM,page,rightmargin);
}

/*---------------------------------------------------------------------------*/
/* setmargins                                                                */
/*---------------------------------------------------------------------------*/
void
setmargins(int topmargin, int bottommargin) {
    int cursorPage = vscrn_current_page_number(VTERM, FALSE);

    if (cursorPage == 0 || on_alternate_buffer(VTERM)) {
        /* Xterm does not provide separate margins for the alternate screen, so
         * they must be kept in sync with the first page */
        vscrn_set_page_margin_top(VTERM, 0, topmargin);
        vscrn_set_page_margin_bot(VTERM, 0, bottommargin);
        vscrn_set_page_margin_top(VTERM, ALTERNATE_BUFFER_PAGE(VTERM), topmargin);
        vscrn_set_page_margin_bot(VTERM, ALTERNATE_BUFFER_PAGE(VTERM), bottommargin);
    } else {
        vscrn_setc_page_margin_top(VTERM,topmargin);
        vscrn_setc_page_margin_bot(VTERM,bottommargin);
    }
}

/*---------------------------------------------------------------------------*/
/* setmargins                                                                */
/*---------------------------------------------------------------------------*/
void
setlrmargins(int leftmargin, int rightmargin) {
    int cursorPage = vscrn_current_page_number(VTERM, FALSE);

    if (cursorPage == 0 || on_alternate_buffer(VTERM)) {
        /* Xterm does not provide separate margins for the alternate screen, so
         * they must be kept in sync with the first page */
        vscrn_set_page_margin_left(VTERM, 0, leftmargin);
        vscrn_set_page_margin_right(VTERM, 0, rightmargin);
        vscrn_set_page_margin_left(VTERM, ALTERNATE_BUFFER_PAGE(VTERM), leftmargin);
        vscrn_set_page_margin_right(VTERM, ALTERNATE_BUFFER_PAGE(VTERM), rightmargin);
    } else {
        vscrn_setc_page_margin_left(VTERM,leftmargin);
        vscrn_setc_page_margin_right(VTERM,rightmargin);
    }
}

/*---------------------------------------------------------------------------*/
/* line25                                                                    */
/*---------------------------------------------------------------------------*/

#define STATUS_MAX 10
char *save_status[STATUS_MAX];
char *save_usertext[STATUS_MAX];
char *save_exittext[STATUS_MAX];
char *save_helptext[STATUS_MAX];
char *save_filetext[STATUS_MAX];
char *save_savefiletext[STATUS_MAX];
char *save_hostname[STATUS_MAX];

void
save_status_line() {
    if ((++status_saved >= (STATUS_MAX - 1)) || (status_saved < 0))
      return;

    if (!(save_status[status_saved] = malloc(MAXTERMCOL+1)))
      return;
    else
      strncpy(save_status[status_saved],statusline,MAXTERMCOL);

    if (!(save_usertext[status_saved] = malloc(MAXTERMCOL+1)))
      return;
    else
      strncpy(save_usertext[status_saved],usertext,MAXTERMCOL);

    if (!(save_exittext[status_saved] = malloc(MAXTERMCOL+1)))
      return;
    else
      strncpy(save_exittext[status_saved],exittext,MAXTERMCOL+1);

    if (!(save_helptext[status_saved] = malloc(MAXTERMCOL+1)))
      return;
    else
      strncpy(save_helptext[status_saved],helptext,MAXTERMCOL+1);

    if (!(save_filetext[status_saved] = malloc(MAXTERMCOL+1)))
      return;
    else
      strncpy(save_filetext[status_saved],filetext,MAXTERMCOL+1);

    if (!(save_savefiletext[status_saved] = malloc(MAXTERMCOL+1)))
      return;
    else
      strncpy(save_savefiletext[status_saved],savefiletext,MAXTERMCOL+1);

    if (!(save_hostname[status_saved] = malloc(MAXTERMCOL+1)))
      return;
    else
      strncpy(save_hostname[status_saved],hostname,MAXTERMCOL+1);
}

void
restore_status_line() {
    if ((status_saved >= (STATUS_MAX - 1)) || (status_saved < 0))
      return;

    if (save_status[status_saved]) {
        strncpy(statusline,save_status[status_saved],MAXTERMCOL);
        free(save_status[status_saved]);
    }

    if (save_usertext[status_saved]) {
        ckstrncpy(usertext,save_usertext[status_saved],sizeof(usertext));
        free(save_usertext[status_saved]);
    }

    if (save_exittext[status_saved]) {
        ckstrncpy(exittext,save_exittext[status_saved],sizeof(exittext));
        free(save_exittext[status_saved]);
    }

    if (save_helptext[status_saved]) {
        ckstrncpy(helptext,save_helptext[status_saved],sizeof(helptext));
        free(save_helptext[status_saved]);
    }

    if (save_filetext[status_saved]) {
        ckstrncpy(filetext,save_filetext[status_saved],sizeof(filetext));
        free(save_filetext[status_saved]);
    }

    if (save_savefiletext[status_saved]) {
        ckstrncpy(savefiletext,save_savefiletext[status_saved],sizeof(savefiletext));
        free(save_savefiletext[status_saved]);
    }

    if (save_hostname[status_saved]) {
        ckstrncpy(hostname,save_hostname[status_saved],sizeof(hostname));
        free(save_hostname[status_saved]);
    }

    status_saved--;
    VscrnIsDirty(VTERM);  /* status line needs to be updated */
}

void
strinsert(char *d, char *s) {
    while (*s)
      *d++ = *s++;
}

/*---------------------------------------------------------------------------*/
/* line25                                                   | Page: View     */
/*---------------------------------------------------------------------------*/
/* Assembles the content of the indicator status line.
 */
char *
line25(int vmode) {
    char *s = statusline, * mode = NULL;
    int  i;
    int numlines, linesleft ;
#ifndef KUI
    int w = VscrnGetWidth(vmode);
#endif /* not KUI */

    if ( scrollstatus[vmode] && !escapestatus[vmode] ) {
        /* we are in scrollback mode -- dynamicly update the status line */
        numlines = ( VscrnGetBegin(vmode, FALSE, TRUE) == 0 ) ?
            VscrnGetEnd(vmode, FALSE, TRUE) + 1 : VscrnGetBufferSize(vmode, FALSE, TRUE) ;

        if (tt_roll[vmode]) {
            linesleft = ( VscrnGetScrollTop(vmode, FALSE) >= VscrnGetBegin(vmode, FALSE, TRUE) ) ?
                    VscrnGetScrollTop(vmode, FALSE) - VscrnGetBegin(vmode, FALSE, TRUE) :
                    VscrnGetScrollTop(vmode, FALSE) - VscrnGetBegin(vmode, FALSE, TRUE)
                        + VscrnGetBufferSize(vmode, FALSE, TRUE) ;
        }
        else {
            linesleft = ( VscrnGetTop(vmode, FALSE, TRUE) >= VscrnGetBegin(vmode, FALSE, TRUE) ) ?
                VscrnGetTop(vmode, FALSE, TRUE) - VscrnGetBegin(vmode, FALSE, TRUE) :
                    VscrnGetTop(vmode, FALSE, TRUE) - VscrnGetBegin(vmode, FALSE, TRUE)
                        + VscrnGetBufferSize(vmode, FALSE, TRUE) ;
        }

       switch (markmodeflag[vmode]) {
       case notmarking:
           mode = "SCROLLBACK" ;
           break;
       case inmarkmode:
           mode = "MARK MODE " ;
           break;
       case marking:
           mode = "MARKING   " ;
           break;
       }

        /* Do special status line. */
        switch ( vmode ) {
        case VCMD:
            sprintf(usertext, "%s Top Line is %d out of %d | Help: Alt-H", mode, linesleft+1, numlines );
            break;
        default:
            sprintf(usertext, "%s Top Line is %d out of %d ", mode, linesleft+1, numlines );
        }
    }

    switch ( vmode ) {
    case VTERM: {
        /* Default Status line field sizes
         * Range	Field     	Length
         * ------   ----------- ---------------------
         *   0- 0	padding		1
         *   1-17	usertext	16
         *  18-31	helptext	14
         *  32-46	exittext	15
         *  47-..   hostname	31-len(filetext)-1
         *  ..-77   filetext	len(filetext)
         *  78-79	padding		2
         *
         * If the hostname field is large enough, two characters of padding will be
         * inserted into the start of it to provide better visual separation from
         * the exittext field.
         *
         * If hostname and filetext are too long to fit into the space available, the
         * exittext field is hidden and its space given over to hostname+filetext.
         *
         * Hostname is then truncated to a minimum of four characters before its just
         * hidden. Filetext will also be hidden if there is insufficient room.
         */

        /* Two less than maximum (80) for some padding */
        int right_margin = VscrnGetWidth(VTERM) - 2;

        /* This field shows, by default, "Command: Alt-X". But it can
         * show other things based on context or user customisation.
         * Its normally 15 columns wide and starts in column 32 if visible.*/
        BOOL show_exit_text = FALSE;
        int exittext_field_position = 32, exittext_field_length = 0;

        /* Hostname + filetext field spans columns 47 through 77 inclusive
         * by default, though this depends on if the exittext field is visible
         * and its length */
        BOOL show_hostname_field = FALSE;
        int end_field_position, end_field_length;
        int hostname_len = 0;
        char* hostnameCopy = 0;

        int filetext_len = strlen(filetext);

        if (exittext[0]) {
            show_exit_text = TRUE;
            exittext_field_length = 15; /* Default length for K-95 */

            /* If the default length isn't long enough, increase it */
            if (strlen(exittext) > exittext_field_length) {
                exittext_field_length = strlen(exittext) + 1;
            }
        }

        if (hostname[0]) {
            show_hostname_field = TRUE;
            hostnameCopy = strdup(hostname);
            hostname_len = (int)strlen(hostnameCopy);
        }

        end_field_position = exittext_field_position + exittext_field_length;
        end_field_length = right_margin - end_field_position;

        if (hostname_len + filetext_len + 1 > end_field_length) {
            show_exit_text = FALSE;
            end_field_position = exittext_field_position;
            end_field_length += exittext_field_length;
        }

        /* build the status line */
        for (i = 0; i < MAXTERMCOL; i++)
            s[i] = ' ';
        if (usertext[0])
            strinsert(&s[01], usertext);    /* Leftmost item */
        if (helptext[0])
            strinsert(&s[18], helptext);

        if (filetext_len > 0) {
            /* Only show the filetext field if we've got enough space. It will take priority
             * over the hostname field. */
            if (filetext_len < end_field_length) {
                strinsert(&s[right_margin - filetext_len], filetext); /* Right-justify it */
            }

            if (show_hostname_field) {
                end_field_length -= filetext_len;       /* Space remaining for hostname */
                if (hostname_len > (end_field_length - 1)) {
                    if (end_field_length < 4) {
                        /* Still not enough room to show it at all. Just drop it. */
                        show_hostname_field = FALSE;
                    } else {
                        int j;
                        for (j = end_field_length; j > 0 && hostnameCopy[j] != ':'; j--);
                        if (j > 0) {            /* Cut off ":service" if any */
                            hostnameCopy[j] = '\0';
                        } else {          /* Or else ... */
                            hostnameCopy[end_field_length - 3] = '.'; /* show ellipsis */
                            hostnameCopy[end_field_length - 2] = '.';
                            hostnameCopy[end_field_length - 1] = '.';
                            hostnameCopy[end_field_length] = '\0';
                        }
                    }
                }
            }
        }

        /* If we've got the space, add a bit more padding between the exittext
         * field and the hostname field (3 characters like the other fields to
         * provide better visual separation from the exittext field). Kermit-95
         * only ever ensured 1 column of padding before. */
        if (hostname_len + 2 < end_field_length) {
            end_field_position += 2;
        }

        /* These fields are only shown if there is room for them and they contain
         * something worth showing */
        if (show_exit_text)
            strinsert(&s[exittext_field_position], exittext);
        if (show_hostname_field) {
            strinsert(&s[end_field_position], hostnameCopy);
        }

        if (hostnameCopy != 0) {
            free(hostnameCopy);
        }

#ifndef KUI
        s[0]=(vscrn[vmode].hscroll==0?0xFE:0x11);
        s[pwidth-1]=((pwidth!=w&&vscrn[vmode].hscroll<w-pwidth)?0x10:0xFE);
#endif /* KUI */
        break;
    }
    case VCMD:
        for (i = 0; i < MAXTERMCOL; i++)
            s[i] = ' ';
        if ( scrollstatus[vmode] || escapestatus[vmode] )
            strinsert(&s[01],usertext);
        else
            strinsert(&s[01],
            "K95 Command Screen | Help: Alt-H | Terminal: CONNECT or Alt-X ");
        break;
    default:
        s = "";
    }
    return s ;
}

/* CHSTR  --  Make a printable string out of a character  */
/*char*
chstr(int c) {
    static char s[8];
    char *cp = s;

    if (c < SP || c == DEL)
      sprintf(cp, "CTRL-%c", ctl(c));
    else
      sprintf(cp, "'%c'\n", c);
    cp = s;
    return (cp);
}*/

/* DOESC  --  Process an escape character argument  */

void
esc25(int h) {
    strcpy(usertext, " ESCAPE");
    if (vik.help > 255 && keyname(vik.help))
        sprintf(helptext, "Help: %s", keyname(vik.help));
    else
        strcpy(helptext, "No Help");
    strcpy(exittext, h ? "" : (esc_exit ? "Exit: c" : "Prompt: c"));
    strcpy(hostname, "" );
    strcpy(filetext, "" ) ;
    VscrnIsDirty(VTERM);  /* status line needs to be updated */
}

void
settermstatus( int y )
{
	/* The VT520 doesn't change the number of lines on screen in response to
 	 * turning the status line on or off, and DEC-STD-070 says "Visual side
	 * effects caused by enabling or disabling the Status Display should
	 * be minimized". Changing the number of terminal lines requires doing
	 * VScrnInit() which wipes the screen - certainly not minimal, and it
	 * breaks terminfo applications that want to turn on the status line. So
	 * instead for the K95 and VT520 terminal types, as well as when we're
     * temporarily forcing the status line to INDICATOR for input (eg search,
     * compose, and set bookmark), we'll do as the VT520  does - show
	 * and hide the status line while leaving the number of terminal lines
	 * alone. The VT520 reserves space at the bottom of the screen for the
	 * status line which is simply blank if its off. Instead we'll grow and
	 * shrink the window height as necessary to accommodate it.
	 *
	 * This behaviour should *probably* apply to the VT320 and VT420, but
	 * as I don't have either of them I can't confirm they behave the same
	 * as the VT520. So for now this is for the K95 and VT520 terminal types
     * only, and if/when I get a VT320 and VT420 it may be for those too.
     * For everything else, well leave the window size alone and instead
	 * add or remove one line from the terminal as K95 has always done in the
	 * past */

	if (ISK95(tt_type_mode) || ISVT520(tt_type_mode) || decssdt_override) {
		/* Change screen height only - not terminal height */
		tt_status[VTERM] = y;
		VscrnSetHeight( VTERM, tt_rows[VTERM]+(tt_status[VTERM]?1:0) );
	}
	else if ( y != tt_status[VTERM] ) {
        int p;
        /* might need to fixup the margins */
        for (p = 0; p < vscrn[VTERM].page_count; p++) {
            int margin = vscrn_page_margin_bot(VTERM,p);
            if ( margin == VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) ) {
                if ( y ) {
                    margin-- ;
                }
                else {
                    margin++ ;
                }
                vscrn_set_page_margin_bot(VTERM, p, margin);
            }
        }
        tt_status[VTERM] = y;
        if ( y ){
            tt_szchng[VTERM] = 2 ;
            tt_rows[VTERM]--;
            VscrnInit( VTERM ) ;  /* Height set here */
            naws();
        }
        else {
            tt_szchng[VTERM] = 1 ;
            tt_rows[VTERM]++;
            VscrnInit( VTERM ) ;  /* Height set here */
            naws();
        }
    }
}

/* ttmacro - allow users to specify a particular macro to be executed when */
/*           a terminal type is chosen.                                    */
void
ttmacro( int tt )
{
    extern int maclvl;                  /* Macro invocation level */
    extern CHAR sstate ;
#ifdef DCMDBUF
    extern struct cmdptr *cmdstk;
#else
    extern struct cmdptr cmdstk[];
#endif /* DCMDBUF */

    extern struct keytab ttyptab[] ;
    extern int nttyp ;
    char macroname[24] ;
    int i, m, l, z ;
    int term_io_sav = term_io;
    term_io = 0;                        /* Disable Terminal Emulator I/O */

    /* Compute the macroname */
    for ( i=0;i<nttyp;i++ )
        if ( tt == ttyptab[i].kwval )
            break;
    sprintf( macroname, "tt_%s", ttyptab[i].kwd ) ;

    /* Lookup the macroname */

    l = maclvl ;
    m = mxlook(mactab, macroname, nmac);
    if (m > -1) {
        debug(F111,"zzstring mxlook",macroname,m);
        if ( IsConnectMode() ) {
            apc_command(APC_LOCAL,macroname);
        } else {
            if ((z = dodo(m,NULL,cmdstk[cmdlvl].ccflgs)) > 0) {
                while (maclvl > l) {                /* Keep going till done with it, */
                    debug(F101,"ttmacro loop maclvl 1","",maclvl);
                    sstate = (CHAR) parser(1);      /* parsing & executing each command, */
                    debug(F101,"ttmacro loop maclvl 2","",maclvl);
                    if (sstate) proto();    /* including protocol commands. */
                }
                debug(F101,"ttmacro loop exit maclvl","",maclvl);
            }
        }
    }
    term_io = term_io_sav;
}

void
settermtype( int x, int prompts )
{
    static int savresetcol = 0;
    static int savtcsr = -1, savtcsl = -1, savfcs = -1;
#ifdef COMMENT
    static int savcp = -1;
#endif /* COMMENT */
    static cell_video_attr_t savcolor = cell_video_attr_init_vio_attribute(0);   /* Terminal color */
    static cell_video_attr_t savgrcol = cell_video_attr_init_vio_attribute(0);   /* Graphics color */
    static cell_video_attr_t savulcol = cell_video_attr_init_vio_attribute(0);   /* Underline color */
    static cell_video_attr_t savblcol = cell_video_attr_init_vio_attribute(0);   /* Blink color */
    static cell_video_attr_t savbocol = cell_video_attr_init_vio_attribute(0);   /* Bold color */
	static cell_video_attr_t savdicol = cell_video_attr_init_vio_attribute(0);   /* Blink color */
    static int savulatt = 0;                 /* Underline attribute */
    static int savrvatt = 0;                 /* Reverse attribute */
    static int savblatt = 0;                 /* Blink attribute */
    static int savcmask = 0;                 /* For saving terminal bytesize */
    static int savedGset[VNUM] = {FALSE,FALSE,FALSE,FALSE};
#ifndef KUI
    static int savstatus = TRUE ;
#else
    static int savstatus = FALSE ;
#endif
    extern int fcharset, pflag, initvik, SysInited ;
    int i,y ;

    tt_type_mode = tt_type = x;

    if (!cell_video_attr_is_null(savcolor)) {             /* Restore this stuff if we */
        colorreset = savresetcol ;
        colornormal = savcolor; /* were ANSI before... */
        colorgraphic = savgrcol;
        colorunderline = savulcol;
        colorblink = savblcol;
        colorbold = savbocol;
		colordim = savdicol;

        trueblink     = savblatt ;
        truereverse   = savrvatt ;
        trueunderline = savulatt ;

        savcolor = cell_video_attr_from_vio_attribute(0);
        savgrcol = cell_video_attr_from_vio_attribute(0);
        savulcol = cell_video_attr_from_vio_attribute(0);
        savblcol = cell_video_attr_from_vio_attribute(0);
        savbocol = cell_video_attr_from_vio_attribute(0);
		savdicol = cell_video_attr_from_vio_attribute(0);
        scrninitialized[VTERM] = 0;
        tt_status_usr[VTERM] = savstatus ;
        settermstatus(tt_status_usr[VTERM]) ;
    }

    if (savcmask) {             /* Restore terminal bytesize */
        cmask = savcmask;
        savcmask = 0;
    }
    if (savtcsl > -1) {         /* Restore character sets */
        tcsl = savtcsl;
        tcsr = savtcsr;
        fcharset = savfcs;
        savtcsl = -1;
    }
    if ( savedGset[VTERM] ) {
        for ( i = 0 ; i < 4 ; i++ )
            G[i] = savedG[VTERM][i] ;
        savedGset[VTERM] = FALSE ;
    }
#ifdef COMMENT
    if (savcp > 0) {            /* Restore code page */
        os2setcp(savcp);
        savcp = -1;
    }
#endif /* COMMENT */

    if (ISK95(tt_type) && cell_video_attr_is_null(savcolor) ) {
        savcolor = colornormal;     /* Save coloration */
        savgrcol = colorgraphic ;
        savulcol = colorunderline ;
        savblcol = colorblink ;
        savbocol = colorbold;
		savdicol = colordim;

        savulatt = trueunderline ;
        savblatt = trueblink ;
        savrvatt = truereverse ;

        /* 0xc0c0c0 on 0x000000 */
        colornormal = cell_video_attr_from_vio_attribute(0x07);     /* Light gray on black */
        colorgraphic = cell_video_attr_from_vio_attribute(0x07);    /* Light gray on black */
        colorunderline = cell_video_attr_from_vio_attribute(0x47);  /* Light gray on Red */
        colorblink = cell_video_attr_from_vio_attribute(0x87);      /* Light gray on dark gray */
        colorbold = cell_video_attr_from_vio_attribute(0x0F);       /* Bright White on black */

#ifndef KUI
        trueunderline = TRUE ;     /* Simulate underline */
#endif /* KUI */

        scrninitialized[VTERM] = 0; /* To make it take effect */

#ifdef COMMENT
		/* I *was* going to have the status line off-by-default like it is on
         * the linux terminal, but I've changed my mind for now. It may end up
		 * being off by default eventually, but I think to do that acceptably
	 	 * requires further work. Because of the way the K95 terminal type
		 * resizes the window rather than then VSCRN when the status line is
		 * turned on or off, having it off by default forces us to choose
		 * between either having a non-standard 25 line default height, or
		 * tring to "fix" the default to 24 lines (potentially overriding the
		 * users prior window size choice) clearing the command screen in the
		 * process. I think if we wanted to keep it off by default *and* 24
		 * lines by default it will require a smarter implementation. */

        /* Turn off the status line */
        savstatus = tt_status_usr[VTERM] ;
        tt_status_usr[VTERM] = FALSE ;
        settermstatus( tt_status_usr[VTERM] ) ;
#endif /* COMMENT */

        VscrnInit(VTERM);           /* Reinit the screen buffer */

        savcmask = cmask;           /* Go to 8 bits */
        cmask = 0xFF;

#ifdef UNICODE
#ifdef CKOUNI
		/* Assume UTF-8 remote by default. Second parameter is ignored for
		 * TX_UTF8. */
		setremcharset(TX_UTF8, -1);
#endif /* CKOUNI */
#endif /* UNICODE */

    }
    else if (ISANSI(tt_type) || ISLINUX(tt_type)) {
        if (parity && prompts) {
 printf("WARNING, ANSI terminal emulation works right only if PARITY is NONE.\n");
 printf("HELP SET PARITY for further information.\n");
        }
        if ( cell_video_attr_is_null(savcolor) ) {
            savcolor = colornormal;     /* Save coloration */
            savgrcol = colorgraphic ;
            savulcol = colorunderline ;
            savblcol = colorblink ;
            savbocol = colorbold;
			savdicol = colordim;

            savulatt = trueunderline ;
            savblatt = trueblink ;
            savrvatt = truereverse ;

			/* real linux console colors, on debian in virtualbox at least, are:
		     *   dim - 85/85/85 (probably darkgrey) on black
			 *   underlined - 0/170/170 (cyan) on black
			 *   italic - 0/170/0 (green) on black
			 *   blink -  170/170/170 (lightgray) on 85/85/85 (probably darkgrey)
			 *   reverse - black on 170/170/170 (lightgray)
			 *   normal - 170/170/170 (lightgray) on black
			 * Probably not something we should default to until we've got a
			 * better alternative terminal type for people to use.
			 */

            colornormal = cell_video_attr_from_vio_attribute(0x07);         /* Light gray on black */
            colorgraphic = cell_video_attr_from_vio_attribute(0x07);        /* Light gray on black */
            colorunderline = cell_video_attr_from_vio_attribute(0x47);      /* Light gray on Red */
            colorblink = cell_video_attr_from_vio_attribute(0x87);          /* Light gray on dark gray */
            colorbold = cell_video_attr_from_vio_attribute(0x0F);          /* Bright White on black */
#ifndef KUI
            trueunderline = FALSE ;     /* Simulate underline */
#endif /* KUI */

            savresetcol = colorreset;     /* Save Reset Color mode */

            if (ISLINUX(tt_type) )
                colorreset = FALSE ;
            else
                colorreset = TRUE ;     /* Turn Reset color mode on */
            scrninitialized[VTERM] = 0; /* To make it take effect */

            savstatus = tt_status_usr[VTERM] ;
            if ( ISUNIXCON(tt_type) ) {
                tt_status_usr[VTERM] = FALSE ;
                settermstatus( tt_status_usr[VTERM] ) ;
            }

            VscrnInit(VTERM);           /* Reinit the screen buffer */

            savcmask = cmask;           /* Go to 8 bits */
            cmask = 0xFF;

            savtcsl = tcsl;             /* Save terminal charset */
            savtcsr = tcsr;
            savfcs  = fcharset;

            if ( ISLINUX(tt_type) ) {
                G[0].def_designation = G[0].designation = TX_ASCII;
                G[0].init = TRUE;
                G[0].def_c1 = G[0].c1 = FALSE;
                G[0].size = cs94;
                G[0].national = FALSE;

                G[1].def_designation = G[1].designation = TX_8859_1;
                G[1].init = TRUE;
                G[1].def_c1 = G[1].c1 = FALSE;
                G[1].size = cs94;
                G[1].national = FALSE;

                G[2].def_designation = G[2].designation = TX_8859_1;
                G[2].init = TRUE;
                G[2].def_c1 = G[2].c1 = FALSE;
                G[2].size = cs94;
                G[2].national = FALSE;

                G[3].def_designation = G[3].designation = TX_DECSPEC;
                G[3].init = TRUE;
                G[3].def_c1 = G[3].c1 = FALSE;
                G[3].size = cs94;
                G[3].national = FALSE;

#ifdef UNICODE
#ifdef CKOUNI
				/* Modern linux uses UTF-8 by default, so if we have unicode
				 * support then override all of the above with UTF-8. Second
				 * parameter is ignored for TX_UTF8. */
				setremcharset(TX_UTF8, -1);
#endif /* CKOUNI */
#endif /* UNICODE */

            } else {
                tcsr = tcsl = TX_ASCII;     /* Make them both the same */
                y = os2getcp();             /* Default is current code page */
                switch (y) {
#ifdef COMMENT
                    /* These do not support box drawing characters */
                case 1250: setremcharset(TX_CP1250,4); break;
                case 1251: setremcharset(TX_CP1251,4); break;
                case 1252: setremcharset(TX_CP1252,4); break;
                case 1253: setremcharset(TX_CP1253,4); break;
                case 1254: setremcharset(TX_CP1254,4); break;
                case 1257: setremcharset(TX_CP1257,4); break;
#endif /* COMMENT */
                case 850:  setremcharset(TX_CP850,4); break;
                case 852:  setremcharset(TX_CP852,4); break;
                case 857:  setremcharset(TX_CP857,4); break;
                case 862:  setremcharset(TX_CP862,4); break;
                case 866:  setremcharset(TX_CP866,4); break;
                case 869:  setremcharset(TX_CP869,4); break;
                case 437: 
                default:   setremcharset(TX_CP437,4); break;
                }
#ifdef COMMENT
                /* These should no longer be necessary with the above */
                if (!cs_is_nrc(tcsl)) {
                    G[0].def_designation = G[0].designation = TX_ASCII;
                    G[0].init = TRUE;
                    G[0].def_c1 = G[0].c1 = FALSE;
                    G[0].size = cs94;
                    G[0].national = FALSE;
                }
                for (i = cs_is_nrc(tcsl) ? 0 : 1; i < 4; i++) {
                    G[i].def_designation = G[i].designation = tcsl;
                    G[i].init = TRUE;
                    G[i].def_c1 = G[i].c1 = FALSE;
                    switch (cs_size(G[i].designation)) { /* 94, 96, or 128 */
                    case 128:
                    case 96:
                        G[i].size = G[i].def_size = cs96;
                        break;
                    case 94:
                        G[i].size = G[i].def_size = cs94;
                        break;
                    default:
                        G[i].size = G[i].def_size = csmb;
                        break;
                    }
                    G[i].national = cs_is_nrc(tcsl);
                }
#endif /* COMMENT */
            }
        }
    }
    else if ( ISAAA(tt_type) ) {
        savtcsl = tcsl;         /* Save terminal charset */
        savtcsr = tcsr;
        savfcs  = fcharset;

        /* Default Character-set is ASCII */
        for ( i = 0 ; i < 4 ; i++ ) {
            savedG[VTERM][i] = G[i] ;
        }
        savedGset[VTERM] = TRUE ;

        G[0].def_designation = G[0].designation = TX_ASCII;
        G[0].init = TRUE;
        G[0].def_c1 = G[0].c1 = FALSE;
        G[0].size = cs94;
        G[0].national = TRUE;

        G[1].def_designation = G[1].designation = TX_ASCII;
        G[1].init = TRUE;
        G[1].def_c1 = G[1].c1 = FALSE;
        G[1].size = cs94;
        G[1].national = TRUE;

        G[2].def_designation = G[2].designation = TX_ASCII;
        G[2].init = TRUE;
        G[2].def_c1 = G[2].c1 = FALSE;
        G[2].size = cs94;
        G[2].national = TRUE;

        G[3].def_designation = G[3].designation = TX_ASCII;
        G[3].init = TRUE;
        G[3].def_c1 = G[3].c1 = FALSE;
        G[3].size = cs94;
        G[3].national = TRUE;
    } 
    else if ( ISHP(tt_type) ) {
        savtcsl = tcsl;         /* Save terminal charset */
        savtcsr = tcsr;
        savfcs  = fcharset;

        /* Default Character-set is HP-ROMAN8 */
        G[0].designation = G[0].def_designation = TX_ASCII ;
        G[0].size = G[0].def_size = cs94 ;
        G[0].c1   = G[0].def_c1 = FALSE ;
        G[0].national = CSisNRC(G[0].designation) ;
        G[0].init = TRUE ;
        for ( i=1; i<4; i++ ) {
            G[i].designation = G[i].def_designation =
                (i == 1) ? TX_HPR8 : TX_HPLINE;
            G[i].size = G[i].def_size = cs96 ;
            G[i].c1   = G[i].def_c1 = TRUE ;
            G[i].init = TRUE ;
        }
        savedGset[VTERM] = TRUE ;
    }
    else if ( ISQNX(tt_type) ) {
        savcmask = cmask;               /* Go to 8 bits */
        cmask = 0xFF;

        savtcsl = tcsl;         /* Save terminal charset */
        savtcsr = tcsr;
        savfcs  = fcharset;

        /* Default Character-set is CP437 */
        for ( i = 0 ; i < 4 ; i++ ) {
            savedG[VTERM][i] = G[i] ;
        }
            G[0].designation = G[0].def_designation = TX_ASCII ;
            G[0].size = G[0].def_size = cs94 ;
            G[0].c1   = G[0].def_c1 = FALSE ;
            G[0].national = CSisNRC(G[0].designation) ;
            G[0].init = TRUE ;
            for ( i=1; i<4; i++ ) {
                G[i].designation = G[i].def_designation =
                    TX_CP437;
                G[i].size = G[i].def_size = cs96 ;
                G[i].c1   = G[i].def_c1 = TRUE ;
                G[i].init = TRUE ;
            }
            savedGset[VTERM] = TRUE ;
    }
    else if ( ISQANSI(tt_type) ) {
        if ( cell_video_attr_is_null(savcolor) ) {
            savcolor = colornormal;     /* Save coloration */
            savgrcol = colorgraphic ;
            savulcol = colorunderline ;
            savblcol = colorblink;
            savbocol = colorbold;
			savdicol = colordim;

            savulatt = trueunderline ;
            savblatt = trueblink ;
            savrvatt = truereverse ;

            colornormal = cell_video_attr_from_vio_attribute(0x07);         /* Light gray on black */
            colorgraphic = cell_video_attr_from_vio_attribute(0x07);        /* Light gray on black */
            colorunderline = cell_video_attr_from_vio_attribute(0x47);      /* Light gray on Red */
            colorblink = cell_video_attr_from_vio_attribute(0x87);          /* Light gray on dark gray*/
            colorbold = cell_video_attr_from_vio_attribute(0x0F);           /* Bright wight on black*/
#ifndef KUI
            trueunderline = FALSE ;     /* Simulate underline */
#endif /* KUI */

            savresetcol = colorreset;     /* Save Reset Color mode */

            colorreset = FALSE ;
            scrninitialized[VTERM] = 0; /* To make it take effect */

            savstatus = tt_status_usr[VTERM] ;
        }

        savcmask = cmask;               /* Go to 8 bits */
        cmask = 0xFF;

        savtcsl = tcsl;         /* Save terminal charset */
        savtcsr = tcsr;
        savfcs  = fcharset;

        /* Default Character-set is ASCII/CP437 */
        for ( i = 0 ; i < 4 ; i++ ) {
            savedG[VTERM][i] = G[i] ;
        }
        /* Set G0 */
        G[0].designation = G[0].def_designation = TX_ASCII ;
        G[0].size = G[0].def_size = cs94 ;
        G[0].c1   = G[0].def_c1 = FALSE ;
        G[0].national = CSisNRC(G[0].designation) ;
        G[0].init = TRUE ;

        /* Set G1 */
        G[1].designation = G[1].def_designation = TX_DECSPEC ;
        G[1].size = G[1].def_size = cs94 ;
        G[1].c1   = G[1].def_c1 = FALSE ;
        G[1].national = CSisNRC(G[1].designation) ;
        G[1].init = TRUE ;

        /* Set G2 */
        G[2].designation = G[2].def_designation = TX_8859_2 ;
        G[2].size = G[2].def_size = cs96 ;
        G[2].c1   = G[2].def_c1 = FALSE ;
        G[2].national = CSisNRC(G[2].designation) ;
        G[2].init = TRUE ;

        /* Set G3 */
        G[3].designation = G[3].def_designation = TX_DECSPEC ;
        G[3].size = G[3].def_size = cs94 ;
        G[3].c1   = G[3].def_c1 = FALSE ;
        G[3].national = CSisNRC(G[3].designation) ;
        G[3].init = TRUE ;
        savedGset[VTERM] = TRUE ;
    }

    GNOW = GL = &G[0] ;
    GR = ISLINUX(tt_type_mode) ? &G[1] : ISVT220(tt_type_mode) ? &G[2] : &G[1];
    SSGL = NULL ;

    if ( ISQNX(tt_type) ) {
        user_erasemode = TRUE;
    }
    else {
        user_erasemode = FALSE;
    }

    if ( IS97801(tt_type_mode) ) {
        dec_lang = VTL_GERMAN;
        dec_nrc = TX_GERMAN;
        dec_kbd = TX_8859_1;
        SNI_bitmode((cmask == 0377) ? 8 : 7);
    }

    if ( ISHFT(tt_type) || ISSCO(tt_type) )
        colorreset = FALSE;
    else
        colorreset = TRUE;

    updanswerbk() ;

    /* only allocate as many pages as required */
    {
        extern int tt_pages[];

        tt_pages[VTERM] = ttype_pages();
        if (user_pages > 0 && user_pages < tt_pages[VTERM]) {
            tt_pages[VTERM] = user_pages;
        }

        /* Add on one page for the alternate screen */
        if (ISK95(tt_type)) {
            tt_pages[VTERM] += 1;
        }
    }

    VscrnInit(VTERM);
    initvik = TRUE;     /* Tell doreset() to initialize the vik table */
    doreset(1);         /* Clear screen and home the cursor */

    ttmacro(x) ;        /* Execute any user defined terminal type macros */

#ifdef KUI
    KuiSetProperty( KUI_TERM_TYPE, (intptr_t) tt_type, (intptr_t) 0 ) ;
#endif /* KUI */
    ipadl25() ;
    VscrnIsDirty(VTERM);
    msleep(10);
}


/*---------------------------------------------------------------------------*/
/* set_term_height                                                           */
/*---------------------------------------------------------------------------*/
/* Sets the terminal height in lines.
 * Used to implement: DECSLPP, DECSNLS, WY52, WY24 */
void
set_term_height(int rows) {
    if ( tt_modechg == TVC_ENA ) {
        tt_szchng[VTERM] = 1 ;
        tt_rows[VTERM] = rows ;
        VscrnInit( VTERM ) ;  /* Height set here */
        naws();
    }
}


/*---------------------------------------------------------------------------*/
/* decscpp                                                                   */
/*---------------------------------------------------------------------------*/
/* Sets the terminal width in columns without clearing the screen  */
void
decscpp(int columns) {
    /* - VTStar, DECterm and K95 emulations allow any number of columns to be
     *   set.
     * - The VT520 and up treat any value greater than 80 as 132, and any value
     *   less than 80 as 80.
     * - Xterm ignores any value that isn't 80 or 132.
     */
    if (columns > 80) {
        switch(tt_type_mode) {
        case TT_XTERM:
            if (columns != 132) return;
            break;
        case TT_VTSTAR:
        case TT_DECTERM:
        case TT_K95:
            break; /* Any width is OK */
        default:
            columns = 132;
            break;
        }
    } else if (columns < 80) {
        switch(tt_type_mode) {
        case TT_XTERM:
            return;
        case TT_VTSTAR:
        case TT_DECTERM:
        case TT_K95:
            break; /* Any width is OK */
        default:
            columns = 80;
            break;
        }
    }

    /* DECSCPP should not clear the screen, regardless of the DECNCSM setting.
     * VscrnInit is the thing that actually does the resizing and clearing, but
     * its called by someone else possibly asynchronously (KClient in GUI
     * builds), and calling it here directly doesn't prevent it from being
     * called again later. So we need a way to signal to VscrnInit that we want
     * the screen contents preserved. This flag is ugly, but it does the job.
     * VscrnInit will reset the flag back to False once its done its job. */
    decscpp_resize = TRUE;

    if (columns < tt_cols[VTERM]) {
        /* DECSCPP should also erase the part of the screen that is being
         * hidden */
        clrrect_escape(VTERM, 1, columns+1,
            VscrnGetHeight(VTERM), VscrnGetWidth(VTERM), SP);
    }

    if (wherex[VTERM] > columns) {
        lgotoxy(VTERM, columns, wherey[VTERM]);
    }

    tt_cols[VTERM] = columns;
    VscrnSetWidth( VTERM, columns);
    naws();
}


/* Gets the VT525 Alternate Colour index to use when the terminal is in
 * Alternate Color mode. */
int get_alternate_color_index(USHORT vtattr) {
    if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                (vtattr & VT_CHAR_ATTR_BLINK) &&
                (vtattr & VT_CHAR_ATTR_REVERSE) &&
                (vtattr & VT_CHAR_ATTR_BOLD))
        return 15;
    else if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                (vtattr & VT_CHAR_ATTR_BLINK) &&
                (vtattr & VT_CHAR_ATTR_REVERSE))
        return 14;
    else if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                (vtattr & VT_CHAR_ATTR_BLINK) &&
                (vtattr & VT_CHAR_ATTR_BOLD))
        return 13;
    else if ((vtattr & VT_CHAR_ATTR_BLINK) &&
                (vtattr & VT_CHAR_ATTR_REVERSE ) &&
                (vtattr & VT_CHAR_ATTR_BOLD))
        return 12;
    else if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                (vtattr & VT_CHAR_ATTR_REVERSE) &&
                (vtattr & VT_CHAR_ATTR_BOLD))
        return 11;
    else if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                (vtattr & VT_CHAR_ATTR_BLINK))
        return 10;
    else if ((vtattr & VT_CHAR_ATTR_BLINK) &&
                (vtattr & VT_CHAR_ATTR_REVERSE))
        return 9;
    else if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                (vtattr & VT_CHAR_ATTR_REVERSE))
        return 8;
    else if ((vtattr & VT_CHAR_ATTR_BLINK) &&
                (vtattr & VT_CHAR_ATTR_BOLD))
        return 7;
    else if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                (vtattr & VT_CHAR_ATTR_BOLD))
        return 6;
    else if ((vtattr & VT_CHAR_ATTR_REVERSE) &&
                (vtattr & VT_CHAR_ATTR_BOLD))
        return 5;
    else if (vtattr & VT_CHAR_ATTR_BLINK)
        return 4;
    else if (vtattr & VT_CHAR_ATTR_UNDERLINE)
        return 3;
    else if (vtattr & VT_CHAR_ATTR_REVERSE)
        return 2;
    else if (vtattr & VT_CHAR_ATTR_BOLD)
        return 1;

	return 0;
}

cell_video_attr_t
ComputeColorFromAttr( int mode, cell_video_attr_t colorattr, USHORT vtattr )
{
    static cell_video_attr_t colorval = cell_video_attr_init_vio_attribute(0x00);
    static cell_video_attr_t _colorattr = cell_video_attr_init_vio_attribute(0x00);
    static USHORT _vtattr=0x00;
	static int _decstglt=100;

    if (decstglt == DECSTGLT_MONO) {
#ifndef KUI
        /* Non-KUI builds can't display colours from the VT525 Mono palette, so
         * we need to convert to the nearest colour in current fixed palette */
        colorattr = cell_video_attr_to_palette(CK_PALETTE_VT525_M, colorattr);
#endif /* KUI */
#ifdef CK_COLORS_24BIT
        /* RGB colors don't use the palette, so switching palettes doesn't
         * affect them. So we must affect them manually! */
        if (!cell_video_attr_fg_is_indexed(colorattr)) {
            int fg = nearest_palette_color_rgb(
                CK_PALETTE_VT525_M,
                cell_video_attr_fg_rgb_r(colorattr),
                cell_video_attr_fg_rgb_g(colorattr),
                cell_video_attr_fg_rgb_b(colorattr));

            colorattr = cell_video_attr_set_fg_color(colorattr, fg);
        }
        if (!cell_video_attr_bg_is_indexed(colorattr)) {
            int bg = nearest_palette_color_rgb(
                CK_PALETTE_VT525_M,
                cell_video_attr_bg_rgb_r(colorattr),
                cell_video_attr_bg_rgb_g(colorattr),
                cell_video_attr_bg_rgb_b(colorattr));

            colorattr = cell_video_attr_set_bg_color(colorattr, bg);
		}
#endif /* CK_COLORS_24BIT */
    }

    if (cell_video_attr_equal(_colorattr, colorattr)
           && vtattr == _vtattr && decstglt == _decstglt)
        goto done;

    colorval = _colorattr = colorattr;
    _vtattr = vtattr;
	_decstglt = decstglt;

    if ((vtattr == VT_CHAR_ATTR_NORMAL && decstglt != DECSTGLT_ALTERNATE) || vtattr == VT_CHAR_ATTR_ERASED)
        goto done;

    if (!(vtattr & WY_CHAR_ATTR) || tt_hidattr)
    {
        if ( (ISWYSE(tt_type_mode) ||
              ISTVI(tt_type_mode) ||
              ISHZL(tt_type_mode))
            && (vtattr & VT_CHAR_ATTR_PROTECTED) ) {
            vtattr = VT_CHAR_ATTR_NORMAL |
           (WPattrib.bold       ? VT_CHAR_ATTR_BOLD      : 0) |
           (WPattrib.dim        ? VT_CHAR_ATTR_DIM       : 0) |
           (WPattrib.underlined ? VT_CHAR_ATTR_UNDERLINE : 0) |
           (WPattrib.blinking   ? VT_CHAR_ATTR_BLINK     : 0) |
           (WPattrib.italic     ? VT_CHAR_ATTR_ITALIC    : 0) |
           (WPattrib.reversed   ? VT_CHAR_ATTR_REVERSE   : 0) |
           (WPattrib.invisible  ? VT_CHAR_ATTR_INVISIBLE : 0) |
           (WPattrib.unerasable ? VT_CHAR_ATTR_PROTECTED : 0) |
           (WPattrib.graphic    ? VT_CHAR_ATTR_GRAPHIC   : 0) |
           (WPattrib.hyperlink  ? VT_CHAR_ATTR_HYPERLINK : 0) |
           (WPattrib.wyseattr   ? WY_CHAR_ATTR           : 0) |
		   (WPattrib.crossedout  ? VT_CHAR_ATTR_CROSSEDOUT:0) ;
        }

        if (vtattr & VT_CHAR_ATTR_HYPERLINK)
            vtattr |= tt_url_hilite_attr;

        if (decstglt == DECSTGLT_ALTERNATE) {
            /* VT525 attributes as colors: This goes beyond what K95 normally
               supports, assigning colors to *combinations* of attributes. Four
               attributes makes 16 different foreground+background combinations.

               These are all stored in decatc_colors which is initialised by
               doreset() and can be set by DECATC only - there is no SET TERMINAL
               command for customising these at this time, as they're only ever
               used when the terminal is put specially in the DECSTGLT alternate
               color mode. This is really only here for VT525-compatibility.
             */

            int idx = get_alternate_color_index(vtattr);

#ifndef KUI
            /* In console builds, color indexes are passed straight to the
             * operating system (OS/2 VIO APIs, or Windows Console Host APIs).
             * So we need to convert the DECATC palette indexes to regular
             * 16-color palette indexes. We *could* do this statically, but
             * converting from one palette to the other lets us handle the host
             * changing the contents of the palette.
             */
            colorval = cell_video_attr_to_palette(CK_PALETTE_VT525_A,
                    decatc_colors[idx]);
#else
            /* In KUI builds, DECSTGLT switches to a compatible color palette
             * so everything just works even though the color indexes are
             * weird */
            colorval = decatc_colors[idx];
#endif /* KUI */

        } else {  /* decstglt != DECSTGLT_ALTERNATE */

            /* Only do attributes-as-colors if either attribute colors always
             * override SGR colors, or if the current characters colors are
             * the default/normal colors */
            if (cell_video_attr_equal(colorattr, defaultattribute)
                || colorAttPriority) {

                if ((vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                    !trueunderline /* underline simulated by color */ )
                    colorval = underlineattribute ;
                else if ((vtattr & VT_CHAR_ATTR_REVERSE) &&
                         !truereverse /* reverse simulated by color */ )
                    colorval = reverseattribute ;
                else if ((vtattr & VT_CHAR_ATTR_ITALIC) &&
                         !trueitalic /* italic simulated by color */ )
                    colorval = italicattribute;
                else if ((vtattr & VT_CHAR_ATTR_CROSSEDOUT) &&
                         !truecrossedout /* crossed-out simulated by color */ )
                    colorval = crossedoutattribute;
                else if ((vtattr & VT_CHAR_ATTR_GRAPHIC))
                    /* a graphic character */
                    colorval = graphicattribute ;
                else if ((vtattr & VT_CHAR_ATTR_BLINK) &&
                        !trueblink && use_blink_attr)
                    /* a blinking character */
                    colorval = blinkattribute ;
                else if ((vtattr & VT_CHAR_ATTR_BOLD) &&
                        !truebold && use_bold_attr)
                    colorval = boldattribute ;
        		else if ((vtattr & VT_CHAR_ATTR_DIM) &&
        				!truedim && dim_is_color)
        			colorval = dimattribute;
                else
                    colorval = colorattr ;
            }

            if ((vtattr & VT_CHAR_ATTR_BLINK) &&
                !trueblink && !use_blink_attr /* blink simulated by BGI */
#ifndef KUI
                || (vtattr & VT_CHAR_ATTR_UNDERLINE) &&
                trueunderline /* underline simulated by BGI */
#endif /* KUI */
                 )
            {
                /* Make the color values intensity bit the opposite of whatever the
                 * current normal foreground (or background in the case of reverse
                 * video) intensity bit is set to.
                 */
                if (decscnm) {
                    if ( fgi )
                        colorval = cell_video_attr_with_fg_intensity_unset(colorval);  /* Toggle FGI */
                    else
                        colorval = cell_video_attr_with_fg_intensity_set(colorval);
                } else {
                    if (bgi)
                        colorval = cell_video_attr_with_bg_intensity_unset(colorval);  /* Toggle BGI */
                    else
                        colorval = cell_video_attr_with_bg_intensity_set(colorval);
                }
            }

            /* Unlike the others, we still *try* to set the intensity bit for bold
             * if the current FG/BG color is <16, because some applications use
             * the bold attribute to access the 8 intense colors. So in K95G,
             * turning off truebold just turns off the bold font without affecting
             * color (unlike turning off trueblink).
             */
            if ( (vtattr & VT_CHAR_ATTR_BOLD && !use_bold_attr
#ifdef KUI
                    && !bold_font_only
#endif /* KUI */
                ) || ( vtattr & VT_CHAR_ATTR_DIM && !dim_is_color
#ifdef KUI
                   && !truedim
#endif /* KUI */
                   )
                 ) {
                if (decscnm) {
                    if (bgi)
                        colorval = cell_video_attr_with_bg_intensity_unset(colorval);  /* Toggle BGI */
                    else
                        colorval = cell_video_attr_with_bg_intensity_set(colorval);
                } else {
                    if ( fgi )
                        colorval = cell_video_attr_with_fg_intensity_unset(colorval);  /* Toggle FGI */
                    else
                        colorval = cell_video_attr_with_fg_intensity_set(colorval);
                }
            }

            if ( vtattr & VT_CHAR_ATTR_REVERSE &&
                truereverse /* not being simulated */ &&
                decstglt != DECSTGLT_ALTERNATE )
                colorval = byteswapcolors(colorval);

        } /* not decstglt == DECSTGLT_ALTERNATE */

        if ( vtattr & VT_CHAR_ATTR_INVISIBLE ) {
#ifdef CK_COLORS_24BIT
			if (!cell_video_attr_bg_is_indexed(colorval)) {
				/* colorval background has an RGB color */
				int r, g, b;
				r = cell_video_attr_bg_rgb_r(colorval);
				g = cell_video_attr_bg_rgb_g(colorval);
				b = cell_video_attr_bg_rgb_b(colorval);
				colorval = cell_video_attr_set_fg_rgb(colorval, r, g, b);
			} else
#endif
            	colorval = cell_video_attr_set_fg_color(colorval,cell_video_attr_background(colorval));
            /* Formerly:
             * colorval = (colorval&0xF0)|((colorval&0xF0)>>4) ;
             *             ^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^
             *             Select BG        Select BG as FG
             * So this copies the current background color to the foreground.
             */
        }
    }

  done:
    if ( flipscrnflag[mode] )
        return byteswapcolors(colorval);
    else
        return colorval;
}

#ifndef NOTERM
/*  V T E S C A P E  --  Interpret a VT52/100/102/220/320 escape sequence  */
/*
  Called after an escape sequence has been received and collected
  into escbuffer[]. To be added:

  Soft character sets (DRCS)
  Request Presentation State Report (DECRQPSR)
  Cursor Information Report (DECCIR)
  Tab Stop Report (DECTABSR)
  Restore Presentation State (DECRSPS)
  Restore Terminal State (DECRSTS)
  many more VT320 specific stuff
*/

/* This used to be 11, but with the addition of SGR-38 and SGR-48 it needed
 * to be bumped up as using the old xterm syntax was bumping up against this
 * limit. For example, this resets everything then sets an RGB FG and RGB BG
 * using 11 PNs:  0;38;2;30;229;12;48;2;163;180;241
 */
#define PN_MAX 22

/* Room for each PN to have 5 elements, not that we'll *ever* need anywhere
 * near this many. The only CSI that uses parameter elements is SGR, and it only
 * uses them  for SGR-38 and SRG-48, so unless someone is intentionally probing
 * for bugs at most only 10 items (5 to set foreground to RGB, 5 to set
 * background to RGB) will ever appear in this list. */
#define PE_MAX 110

static int   pn[PN_MAX]={0,0,0,0,0,0,0,0,0,0,0};
static int   pe[PE_MAX];
/* Where in pe each pn's list of pe's starts. -1 for no list of pe. */
static int   pn_pe_start[PN_MAX]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
static int   pn_pe_count[PN_MAX]={0,0,0,0,0,0,0,0,0,0,0};
static bool  private=FALSE;
static bool  ansiext=FALSE;
static bool  zdsext=FALSE;
static bool  kermext=FALSE;
static vtattrib blankattrib={0,0,0,0,0,0,0,0,0,0,0,1 /* erased */,0,0};

void
vtcsi(void)
{
    unsigned short  j;
    unsigned short  k; /* Number of pn */
    unsigned short  l;
    viocell         blankvcell ;
    int             i;
    char            tempstr[20];
    unsigned short  pecount = 0;  /* Number of pe */
    int             vmode = VTERM;
    /* Currently everything here assumes terminal emulation only ever happens on
     * VTERM and, selectively, VSTATUS. Ideally that restriction would be lifted
     * someday in which case a vmode parameter will have to be introduced. Until
     * then, the hardcoded VTERMs can be progressively replaced with the above
     * vmode variable. */

    if ( ISH19(tt_type_mode) ) {
        /* Hold Screen Mode On */
        /* They must have been drunk when they did this one */
        ;
    }
    else
    {
        achar = (escnext<=esclast)?escbuffer[escnext++]:0;
     LB2000:
        switch (achar) {        /* Second level */
        case 'A':               /* CUU - Cursor up one line */
            if ( IS97801(tt_type_mode) ) {
                /* ignored if outside scroll region */
                if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                    wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                    break;
            }
            cursorup(0);
            if ( !ISANSI(tt_type_mode) || ISLINUX(tt_type_mode))
                wrapit = FALSE;
            break;
        case 'B':               /* CUD - Cursor down one line */
            if ( IS97801(tt_type_mode) ) {
                /* ignored if outside scroll region */
                if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                    wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                    break;
            }
            cursordown(0);
            if ( !ISANSI(tt_type_mode) || ISLINUX(tt_type_mode) )
                wrapit = FALSE;
            break;
        case 'C':               /* CUF - Cursor forward, stay on same line */
            if (tt_type == TT_VT100 || tt_type == TT_VT102) {
                /* The VT10x and only the VT10x does not reset the
                 * LCF on CUF. The VT220 and VT520 when emulating a VT100 do.
                 * cursorright() always resets the LCF, so take a backup before
                 * calling.
                 */
                bool lcf = wrapit;
                cursorright(0);
                wrapit = lcf;
            }
            else {
                cursorright(0);
            }
            break;
        case 'D':               /* CUB - Cursor back, stay on same line */
            cursorleft(0);
            break;
        case 'E':
            if ( ansiext && ISBA80(tt_type_mode) ) {
                /* Window Status Request */
                char buf[64];
                sprintf(buf,"%c[=D%3d:%3d;001:001;Lohn    D",
                         27,VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0),
                         VscrnGetWidth(VTERM));
                ttol(buf,strlen(buf));

            }
            else if ( private && ISAIXTERM(tt_type_mode) ) {
                /* Erase Status Line */
                clrscreen(VSTATUS,SP);
                break;
            }
            else {
                /* CNL - Cursor Next Line */
                cursornextline(FALSE, 1);
            }
            break;
        case 'F':
            if ( private && ISAIXTERM(tt_type_mode) ) {
                /* Return from Status Line */
                setdecssdt(SASD_TERMINAL);
                break;
            }
            else {
                /* Cursor Previous Line */
                cursorprevline(1);
            }
            break;
        case 'J': /* Erase from cursor to end of scrn */
            if (private)
                selclreoscr_escape(VTERM,SP);
            else {
                if ( IS97801(tt_type_mode) ) {
                    /* ignored if outside scroll region */
                    if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                        wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                        break;
                }
                clreoscr_escape(VTERM,SP);
            }

            if (tt_type != TT_VT100 && tt_type != TT_VT102) {
                /* The VT10x and only the VT10x do not clear the LCF on
                 * erase display. The VT220 and VT520 emulating a VT100 do. */
                wrapit = FALSE;
            }
            break;
        case 'V': /* PP - Preceding Page */
			if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
				if (!on_alternate_buffer(VTERM)) {
					previous_page(VTERM, pn[1]);
					lgotoxy(VTERM,1,1);
				}
            } /* Erase from cursor to end of region */
            else if ( ISSCO(tt_type_mode) )
                clreoreg_escape(VTERM,SP);
            break;
        case 'K':
            if ( ansiext && ISBA80(tt_type_mode) ) {
                /* Begin Reading Function Labels */
                ba80_fkey_read = -1;
            }
                /* Erase from cursor to end of line */
            else {
                if ( private == TRUE )
                    selclrtoeoln(VTERM,SP);
                else
                    clrtoeoln(VTERM,SP);

                if (tt_type != TT_VT100 && tt_type != TT_VT102) {
                    /* The VT10x and only the VT10x do not clear the LCF on
                     * erase line. The VT220 and VT520 emulating a VT100 do. */
                    wrapit = FALSE;
                }
            }
            break;
        case '?':               /* DEC private */
            private = TRUE;
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            goto LB2000;
        case '=':               /* SCO,Unixware,ANSI,Nixdorf ext. */
            ansiext = TRUE ;
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            goto LB2000;
        case '>':               /* Heath/Zenith/AnnArbor/xterm extension */
            zdsext = TRUE ;
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            goto LB2000;
        case '<':               /* Kermit extension */
            kermext = TRUE ;
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            goto LB2000;
        case 'H':
            if ( private && ISHFT(tt_type_mode) ) {
                /* Hide Status Line */
                setdecssdt( SSDT_INDICATOR );
                break;
            }
            /* (no break) Cursor Home */
        case 'f':  /* HVP */
            if ( IS97801(tt_type_mode) && decsasd == SASD_STATUS )
                setdecsasd(SASD_TERMINAL);
            home_cursor(vmode);
            break;
        case 'g':
            if ( !ISSCO(tt_type_mode) ) {
                /* Tab Clear at this position */
                htab[wherex[VTERM]] = '0';
            }
            break;
        case 'm':       /* Normal Video - Exit all attribute modes */
            if (colorreset)
                resetcolors(0) ;

            attrib.blinking = FALSE;
            attrib.italic = FALSE;              /* No italic */
            attrib.bold = FALSE;
            attrib.invisible = FALSE;
            attrib.underlined = FALSE;
            attrib.reversed = FALSE;
            attrib.dim = FALSE ;
            attrib.graphic = FALSE ;
            attrib.wyseattr = FALSE ;
			attrib.crossedout = FALSE ;
            attrib.erased = FALSE;
            attrib.hyperlink = FALSE;
            attrib.linkid = 0;

            sco8bit = FALSE ;

            if ( ISANSI(tt_type_mode) )
                crm = FALSE ;
            break;
        case 'M':
            if ( ansiext && ISBA80(tt_type_mode) ) {
                /* Goto Status Line */
                setdecssdt( SSDT_HOST_WRITABLE );
                setdecsasd( SASD_STATUS );
                break;
            }
            else {
                pn[1] = 1;
                k = 1;
                goto LB2003;
            }
            break;
        case 'r': 
#ifdef COMMENT
            /* Reset Margin */
            setmargins(1, VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0));
            if ( decsasd == SASD_STATUS )
                lgotoxy( VSTATUS, 1, 1 );
            else
                lgotoxy(VTERM, 1, 1);
#else /* COMMENT */
            if ( ISSUN(tt_type_mode) ) {
                pn[1] = 0;
                k = 1;
            } else {
                pn[1] = pn[2] = 1;
                k = 2;
            }
            goto LB2003;
#endif /* COMMENT */
            break;
        case 's': 
            if ( ISSUN(tt_type_mode) ) {
                doreset(1);
            } else if (declrmm &&
                        (decsasd == SASD_TERMINAL || ISXTERM(tt_type_mode)) &&
                        IS_DECLRMM_AVAILABLE(tt_type_mode)) {
                /* DECSLRM - Set Left/Right Margins (reset) -------------------
                 * Sets Left/Right margins only if Left/Right Margin Mode is
                 * enabled. The VT520 and VT420 ignore DECSLRM if the cursor is
                 * currently on the status line. This behaviour is not described
                 * by DEC STD-070, and XTERM does not implement it.
                 */
				setlrmargins(1, VscrnGetWidth(VTERM));
                home_cursor(vmode);
			} else
            /* ANSI.SYS save cursor position */
            if ( ISANSI(tt_type_mode) ||
                 ISLINUX(tt_type_mode) ||
                 ISXTERM(tt_type_mode) ||
                 (ISK95(tt_type_mode) && !declrmm))
                savecurpos(VTERM,0); /* SCOSC */
            break;
        case 'u': /* ANSI.SYS restore cursor position */
            if ( ISANSI(tt_type_mode) ||
                IS97801(tt_type_mode))
                restorecurpos(VTERM,0);
            break;
        case 'U': /* NP - Next Page */
            if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
				if (!on_alternate_buffer(VTERM)) {
					next_page(VTERM, 0);
					lgotoxy(VTERM,1,1);
				}
			} else if ( ISSCO(tt_type_mode) ) { /* SCO ANSI Reset Initial Screen */
                doreset(1);   /* Hard Reset */
			}
            break;
        case '!':
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            switch (achar) {
            case 'p':
                doreset(0);   /* DECSTR - Soft Reset */
                break;
            }
            break;
        case '$':
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            switch (achar) {
            case '}':
                /* DECSASD - Select Active Status Display */
                setdecsasd( SASD_TERMINAL );
                break;
            case '-':   /* VT320 */
            case '~':   /* WY370 */
                /* DECSSDT - Select Status Line Type */
                setdecssdt( SSDT_BLANK );
                break;
            case '|':   /* DECSCPP */
                decscpp(80);
                break;
            case 'u':    /* DECRQTSR - default is ignored */
                break;
            }
            break;
        case 'S':
            if ( private && ISAIXTERM(tt_type_mode) ) {
                /* Show Status Line */
                setdecssdt( SSDT_HOST_WRITABLE );
                break;
            } else if ( ansiext && ISBA80(tt_type_mode) ) {
                /* Return from Status Line */
                setdecsasd(SASD_TERMINAL);
                break;
            }
            else {
                pn[1] = 1;
                k = 1;
                goto LB2003;
            }
            break;
        case 'a':
        case 'e':
        case 'T':
        case 'L':
        case '@':
        case 'P':
		case 'Z':
        case SP:
            pn[1] = 1;
            k = 1;
            goto LB2003;
        case 'c':
        case 'h':
        case 'l':
        case 'n':
        case 'x':
            pn[1] = 0;
            k = 1;
            goto LB2003;
        case ';':               /* As in ESC [ ; 7 m */
            pn[1] = 0;
            k = 1;
            goto LB2002;
        default:  {             /* Pn - got a number */
          /*LB2001:*/
            /* Esc [ Pn...Pn x   functions */
            pn[1] = pnumber(&achar);
            k = 1;
          LB2002:
			pecount=0;
            while (achar == ';' || achar == ':') { /* get Pn[k] */
				int is_pe = (achar == ':');
                achar = (escnext<=esclast)?
                    escbuffer[escnext++]:0;

                /* If there is a '?' at this point it is a protocol */
                /* error.  We will skip over it since this appears  */
                /* to be a frequent mistake that people make when   */
                /* combining private parameters.                    */
                if (achar == '?')
                    achar = (escnext<=esclast)?
                        escbuffer[escnext++]:0;

				if (!is_pe) { /* Handle parameter */
					if (k < PN_MAX-1) k++;
                	pn[k] = pnumber(&achar);
					pn_pe_start[k] = -1;
					pn_pe_count[k] = 0;
				} else { /* Handle parameter element */
					if (pecount < PE_MAX - 1) pecount++;
					pe[pecount] = pnumber(&achar);
					if (pn_pe_start[k] == -1) pn_pe_start[k] = pecount;
					pn_pe_count[k]++;
				}
            }
            pn[k + 1] = 1;
          LB2003:
            switch (achar) { /* Third level */
            case '"':
                achar = (escnext<=esclast)?
                    escbuffer[escnext++]:0;
                switch (achar) {
                case 'p': /* COMPATIBILITY LEVEL (DECSCL) */
                    setdecsasd(SASD_TERMINAL);
                    switch ( pn[1] ) {
                    case 61:
                        switch ( tt_type ) {
                        case TT_VT100:
                            tt_type_mode = TT_VT100 ;
                            break;
                        case TT_VT102:
                        case TT_VT220:
                        case TT_VT220PC:
                        case TT_VT320:
                        case TT_VT320PC:
                        case TT_WY370:
                            tt_type_mode = TT_VT102 ;
                            break;
                        }
                        break;
                    case 62:
                        switch ( tt_type ) {
                        case TT_VT220:
                        case TT_VT220PC:
                        case TT_VT320:
                        case TT_VT320PC:
                        case TT_WY370:
                            tt_type_mode = tt_type;
                            break;
                        }
                        if ( k > 1 && pn[2] == 1 )
                            send_c1 = FALSE ; /* 7-bit cntrols */
                        else
                            send_c1 = TRUE ; /* 8-bit controls */
                        break;
                    case 63:
                        switch (tt_type) {
                        case TT_VT320:
                        case TT_VT320PC:
                        case TT_WY370:
                            tt_type_mode = tt_type ;
                            if ( k > 1 && pn[2] == 1 )
                                send_c1 = FALSE ; /* 7-bit */
                            else
                                send_c1 = TRUE ; /* 8-bit */
                        }
                        break;
                    }
                    ipadl25();
                    break;
                case 'q':
                    /* DECSCA - Select Character Attributes */
                    if ( ISVT220(tt_type_mode) ) {
                        switch (pn[1]) {
                        case 0:  /* Reset all attributes */
                        case 2:  /* Designate character erasable */
                            attrib.unerasable = FALSE ;
                            break;
                        case 1:  /* Designate character unerasable */
                            attrib.unerasable = TRUE ;
                            break;
                        default:
                            break;
                        }
                    }
                    break;
                case 'v':
                    if ( ISVT220(tt_type_mode) ) {
                        /* DECRQDE - Windows Reports */
                        char decrpde[32] ;
                        sprintf(decrpde,"[%d;%d;%d;%d;%d\"w",
                                 VscrnGetHeight(VTERM),
                                 VscrnGetWidth(VTERM),
                                 1,
                                 1,
                                 vscrn[vmode].cursor.p+1);
                        sendescseq(decrpde);
                    }
                    break;
                default:
                    break;
                }
                break;
            case '$':
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch (achar) {
                case '}':
                    /* DECSASD - Select Active Status Display */
                    setdecsasd( pn[1] );
                    break;
                case '-': /* DEC VT320 */
                case '~': /* WYSE 370  */
                    /* DECSSDT - Select Status Line Type */
                    setdecssdt( pn[1] );
                    break;
                case '|':
                    /* DECSCPP - Set Columns Per Page */
                    decscpp(k < 1 ? 80 : pn[1]);
                    break;
                case 'p': {     /* DECRQM (from host) */
                    char buf[16] ;
                    if ( private ) {
                        switch ( pn[1] ) {
                        case 1: /* DECCKM */
                            pn[2] = (tt_arrow == TTK_APPL) ? 1 : 2 ;
                            break;
                        case 2: /* DECANM */
                            pn[2] = (tt_type_mode == tt_type_vt52) ?
                                1 : 2 ;
                            break;
                        case 3: /* DECCOLM */
                            pn[2] = deccolm ? 1 : 2 ;
                            break;
                        case 4: /* DECSCLM */
#ifdef KUI
                            pn[2] = scrollmode >= TTS_SMOOTH ? 1 : 2 ;
#else
                            pn[2] = updmode >= TTU_SMOOTH ? 1 : 2 ;
#endif /* KUI */
                            break;
                        case 5: /* DECSCNM */
                            pn[2] = decscnm ? 1 : 2 ;
                            break;
                        case 6: /* DECOM */
                            pn[2] = relcursor ? 1 : 2 ;
                            break;
                        case 7: /* DECAWM */
                            pn[2] = tt_wrap ? 1 : 2 ;
                            break;
                        case 8: /* DECARM */
#ifdef NT
                            pn[2] = tt_autorepeat ? 1 : 2 ;
#else /* NT */
                            pn[2] = 3 ; /* permanently set */
#endif /* NT */
                            break;
                        case 9: /* DECINLM - Interlace */
#ifdef OS2MOUSE
                            /* X10 mouse reporting */
                            if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {

                                pn[2] = MOUSE_REPORTING_TEST_FLAG(
                                    mouse_reporting_mode,
                                    MOUSEREPORTING_X10) ? 1 : 2;
                                }
#endif
                            break;
                        case 10:        /* DECEDM - Block mode off */
                            if (ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                /* Toolbar off (rxvt) */
                                /* Default to permanently reset in case not KUI
                                 * or NOTOOLBAR */
                                pn[2] = 4;
#ifdef KUI
#ifndef NOTOOLBAR
                                pn[2] = KuiGetProperty(KUI_GUI_TOOLBAR_VIS, 0L) ? 1 : 2;
#endif
#endif
                            }
                            break;
                        case 12: /* AT&T 610/xterm - cursor blinking */
                            pn[2] = tt_cursor_blink == 1 ? 1 : 2;
                            break;
                        case 18: /* DECPFF */
                            pn[2] = xprintff ? 1 : 2 ;
                            break;
                        case 19: /* DECPEX */
                            pn[2] = !printregion ? 1 : 2 ;
                            break;
                        case 25: /* DECTCEM */
                            pn[2] = cursorena[VTERM] ? 1 : 2 ;
                            break;
                        case 42: /* DECNRCM */
                            pn[2] = decnrcm ? 1 : 2 ;
                            break;
                        case 64: /* DECPCCM */
                            /* Page cursor coupling */
                            if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
                                pn[2] = vscrn[VTERM].page_cursor_coupling ? 1 : 2;
                            } else {
                                pn[2] = 3; /* permanently set */
                            }
                            break;
                        case 66: /* DECNKM */
                            pn[2] = tt_keypad == TTK_APPL ? 1 : 2 ;
                            break;
                        case 67: /* DECBKM */
                            pn[2] = keymap[KEY_SCAN|8] == BS ? 1 : 2 ;
                            break;
                        case 68: /* DECKBUM */
                            pn[2] = 3 ; /* permanently set */
                            break;
                        case 69: /* DECLRMM aka DECVSSM */
                            if (IS_DECLRMM_AVAILABLE(tt_type_mode)) {
                                pn[2] = declrmm ? 1 : 2;
                            }
                            break;
                        case 95:
                            if (ISVT520(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                pn[2] = decncsm ? 1 : 2;
                            }
                            break;
                        case 114: /* DECATCUM */
                            pn[2] = decatcum ? 1 : 2;
                            break;
                        case 115: /* DECATCBM */
                            pn[2] = decatcbm ? 1 : 2;
                            break;
                        case 116: /* DECBBSM */
                            break;
                        case 117: /* DECECM */
                            /* On - erase with default/normal colour,
                             * Off - erase with current attribute colour */
                            pn[2] = erasemode == 0 ? 2 : 1;
                            break;
                        case 1000:
#ifdef OS2MOUSE
                            /* X11 mouse reporting */
                            if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {

                                pn[2] = MOUSE_REPORTING_TEST_FLAG(
                                    mouse_reporting_mode,
                                    MOUSEREPORTING_X11) ? 1 : 2;
                                }
#endif
                            break;
                        case 1002:
#ifdef OS2MOUSE
                            /* X11 mouse reporting */
                            if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {

                                pn[2] = MOUSE_REPORTING_TEST_FLAG(
                                    mouse_reporting_mode,
                                    MOUSEREPORTING_BTNEVENT) ? 1 : 2;
                                }
#endif
                            break;
                        case 1003:
#ifdef OS2MOUSE
                            /* X11 mouse reporting */
                            if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {

                                pn[2] = MOUSE_REPORTING_TEST_FLAG(
                                    mouse_reporting_mode,
                                    MOUSEREPORTING_ANYEVENT) ? 1 : 2;
                                }
#endif
                            break;
                        case 1004:
#ifdef KUI
                            pn[2] = transmit_focus_change ? 1 : 2;
#else /* KUI */
                            pn[2] = 4; /* permanently reset */
#endif /* KUI */
                            break;
                        case 1006:
#ifdef OS2MOUSE
                            /* X11 mouse reporting */
                            if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {

                                pn[2] = MOUSE_REPORTING_TEST_FLAG(
                                    mouse_reporting_mode,
                                    MOUSEREPORTING_SGR) ? 1 : 2;
                                }
#endif
                            break;
                        case 1011:
                            pn[2] = tt_rkeys[VTERM] == TTRK_RST ? 1 : 2 ;
                            break;
                        case 1015:
#ifdef OS2MOUSE
                            /* X11 mouse reporting */
                            if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {

                                pn[2] = MOUSE_REPORTING_TEST_FLAG(
                                    mouse_reporting_mode,
                                    MOUSEREPORTING_URXVT) ? 1 : 2;
                                }
#endif
                            break;
                        case 1034:  /* xterm - Interpret "meta" key */
                            pn[2] = tt_kb_mode == KBM_MM ? 1 : 2;
                            break;
                        case 1036:  /* xterm - Send esc when Meta modifies a key */
                            pn[2] = tt_kb_mode == KBM_ME ? 1 : 2;
                            break;
                        case 1042:  /* xterm - urgency window hint on bell */
#ifdef KUI
                            pn[2] = tt_bell_flash ? 1 : 2;
#else
                            pn[2] = 4; /* Permanently reset */
#endif /* KUI */
                            break;
                        case 1043:  /* xterm - raise window on bell */
#ifdef KUI
                            pn[2] = tt_bell_raise ? 1 : 2;
#else
                            pn[2] = 4; /* Permanently reset */
#endif /* KUI */
                            break;
                        case 1046:    /* xterm - disallow switching to alternate screen? */
                            if (ISK95(tt_type) || ISXTERM(tt_type)) {
                                pn[2] = vscrn[vmode].allow_alt_buf ? 1 : 2;
                            } else {
                                pn[2] = 4; /* Permanently reset */
                            }
                            break;
                        case 1047:    /* xterm - alternate screen */
                        case 1049:
                            if (ISK95(tt_type) || ISXTERM(tt_type)) {
                                int page, alternate_screen_page;
                                page = vscrn[vmode].cursor.p;
                                alternate_screen_page = ALTERNATE_BUFFER_PAGE(vmode);
                                pn[2] = page == alternate_screen_page ? 1 : 2;
                            } else {
                                pn[2] = 4; /* Permanently reset */
                            }
                            break;
                        case 1048:    /* xterm - cursor saved? */
                            if (ISK95(tt_type) || ISXTERM(tt_type)) {
                                pn[2] = saved[vmode] ? 1 : 2 ;
                            } else {
                                pn[2] = 0;
                            }
                            break;

                        case 2004:
                            pn[2] = bracketed_paste[vmode] ? 1 : 2;
                            break;
                        case 2026:
                            if (ISK95(tt_type_mode)) {
#ifdef KUI
                                pn[2] = tt_sync_output ? 1 : 2;
#else
                                pn[2] = 4; /* Permanently reset */
#endif /* KUI */
                            }
                            break;

                        default:
                            pn[2] = 0 ; /* Unrecognized mode */
                            break;
                        }
                        sprintf(buf,"[?%d;%d$y",pn[1],pn[2]);
                    }
                    else {
                        switch ( pn[1] ) {
                        case 2: /* KAM */
                            pn[2] = keylock ? 1 : 2 ;
                            break;
                        case 3: /* CRM */
                            pn[2] = crm ? 1 : 2 ;
                            break;
                        case 4: /* IRM */
                            pn[2] = insertmode ? 1 : 2 ;
                            break;
                        case 10: /* HEM */
                            pn[2] = 4 ; /* permanently reset */
                            break;
                        case 12: /* SRM */
                            pn[2] = !duplex ? 1 : 2 ;
                            break;
                        case 20: /* LNM */
                            pn[2] = tt_crd && tnlm ? 1 : 2 ;
                            break;
                        default:
                            pn[2] = 0 ; /* unrecognized mode */
                            break;
                        }
                        sprintf(buf,"[%d;%d$y",pn[1],pn[2]);
                    }
                    sendescseq(buf);
                    break;
                }
                case 'R':
                    if ( ISBA80(tt_type_mode) && ansiext ) {
                        /* Reset virtual window to the background */
                    } else if ( ISSCO(tt_type_mode)) {
                        /* Delete lines - Alternate form of (CSI P1 M) */
                        for (i = 1; i <= pn[1]; ++i) {
                            VscrnScroll(VTERM,
                                         UPWARD,
                                         wherey[ VTERM] - 1,
                                         vscrn_c_page_margin_bot(VTERM) - 1,
                                         1,
                                         FALSE,
                                         SP,
                                         FALSE);
                        }
                        VscrnIsDirty(VTERM);
                    }
                    break;
                case 'r':       /* DECCARA - Change Attr in Rect Area */
                    if ( ISVT420(tt_type_mode) )
                    {
                        /* Because of malformed SGR-38/48 sequences, this needs
                         * to be able to advance j as well as access to any
                         * parameter elements for this CSI sequence */
                        change_attributes_in_rectangle(vmode, pn, k, &j, pe,
                            pn_pe_start, pn_pe_count);
                    }
                    break;
                case 't':       /* DECRARA - Reverse Attr in Rect Area */
                    if ( ISVT420(tt_type_mode) )
                    {
                        int w, h, x, y, z;
                        /*
                         * pn[1] - top-line border      default=1
                         * pn[2] - left-col border      default=1
                         * pn[3] - bottom-line border   default=last line
                         * pn[4] - right col border     default=last column
                         * pn[5] -> pn[k] attributes to change - default=0
                         *
                         *  0 - reverse all attributes
                         *  1 - reverse bold
                         *  4 - reverse underline
                         *  5 - reverse blink
                         *  7 - reverse negative image
                         *
                         * decsace == FALSE, stream else rectangle
                         */

                        if ( k < 1 || pn[1] == 0 ) pn[1] = 1;
                        if ( k < 2 || pn[1] == 0 ) pn[2] = 1;
                        if ( k < 3 || pn[1] == 0 ) pn[3] = VscrnGetHeight(VTERM)
                             -(tt_status[VTERM]?1:0);
                        if ( k < 4 || pn[1] == 0 ) pn[4] = VscrnGetWidth(VTERM);
                        if ( k < 5 || pn[1] == 0 ) {
                            pn[5] = 0;
                            k = 5;
                        }

                        if (relcursor) {
                            /* Add top and left margins to the vertical and
                             * horizontal coordinates */
                            pn[1] += vscrn_c_page_margin_top(VTERM)-1; /* top */
                            pn[2] += vscrn_c_page_margin_left(VTERM)-1;/* lft */
                            pn[3] += vscrn_c_page_margin_top(VTERM)-1; /* bot */
                            pn[4] += vscrn_c_page_margin_left(VTERM)-1;/* rt */

                            if (pn[3] > vscrn_c_page_margin_bot(VTERM))
                                pn[3] = vscrn_c_page_margin_bot(VTERM);
                            if (pn[4] > vscrn_c_page_margin_right(VTERM))
                                pn[4] = vscrn_c_page_margin_right(VTERM);
                        }

                        if ( pn[3] < pn[1] || pn[4] < pn[2] )
                            break;

                        w = pn[4] - pn[2] + 1;
                        h = pn[3] - pn[1] + 1;

                        if ( decsace ) {        /* rectangle */
                            for ( y=0; y<h; y++ ) {
                                videoline * line = VscrnGetLineFromTop(VTERM, pn[1]+y-1, FALSE);
                                for ( x=0; x<w; x++ ) {
                                    for ( z=5; z<=k; z++ ) {
                                        USHORT a = line->vt_char_attrs[pn[2]+x-1];
                                        if (a == VT_CHAR_ATTR_ERASED) {
                                            /* In rectangle mode, unoccuped (erased)
                                             * character positions are changed to
                                             * blanks (become unerased) */
                                            a = VT_CHAR_ATTR_NORMAL;
                                        }
                                        if (pn[z] == 0 || pn[z] == 1) {
                                            if ( a & VT_CHAR_ATTR_BOLD )
                                                a &= ~VT_CHAR_ATTR_BOLD;
                                            else
                                                a |= VT_CHAR_ATTR_BOLD;
                                        }
                                        if (pn[z] == 0 || pn[z] == 4) {
                                            if ( a & VT_CHAR_ATTR_UNDERLINE )
                                                a &= ~VT_CHAR_ATTR_UNDERLINE;
                                            else
                                                a |= VT_CHAR_ATTR_UNDERLINE;
                                        }
                                        if (pn[z] == 0 || pn[z] == 5) {
                                            if ( a & VT_CHAR_ATTR_BLINK )
                                                a &= ~VT_CHAR_ATTR_BLINK;
                                            else
                                                a |= VT_CHAR_ATTR_BLINK;
                                        }
                                        if (pn[z] == 0 || pn[z] == 7) {
                                            if ( a & VT_CHAR_ATTR_REVERSE )
                                                a &= ~VT_CHAR_ATTR_REVERSE;
                                            else
                                                a |= VT_CHAR_ATTR_REVERSE;
                                        }
                                        line->vt_char_attrs[pn[2]+x-1] = a;
                                    }
                                }
                            }
                        } else {                /* stream */
                            for ( y=0; y<h; y++ ) {
                                videoline * line = VscrnGetLineFromTop(VTERM, pn[1]+y-1, FALSE);
                                int rlimit = relcursor ? vscrn_c_page_margin_right(VTERM) : VscrnGetWidth(VTERM);
                                int llimit = relcursor ? vscrn_c_page_margin_left(VTERM)-1 : 0;
                                for ( x = (y==0 ? pn[2] - 1 : llimit);
                                      x < ((y==h-1) ? pn[4] : rlimit);
                                      x++ ) {
                                    if (line->vt_char_attrs[x] == VT_CHAR_ATTR_ERASED) {
                                        /* In stream mode, DECRARA doesn't affect
                                         * unoccupied (erased) character positions */
                                        continue;
                                    }
                                    for ( z=5; z<=k; z++ ) {
                                        USHORT a = line->vt_char_attrs[x];
                                        if (pn[z] == 0 || pn[z] == 1) {
                                            if ( a & VT_CHAR_ATTR_BOLD )
                                                a &= ~VT_CHAR_ATTR_BOLD;
                                            else
                                                a |= VT_CHAR_ATTR_BOLD;
                                        }
                                        if (pn[z] == 0 || pn[z] == 4) {
                                            if ( a & VT_CHAR_ATTR_UNDERLINE )
                                                a &= ~VT_CHAR_ATTR_UNDERLINE;
                                            else
                                                a |= VT_CHAR_ATTR_UNDERLINE;
                                        }
                                        if (pn[z] == 0 || pn[z] == 5) {
                                            if ( a & VT_CHAR_ATTR_BLINK )
                                                a &= ~VT_CHAR_ATTR_BLINK;
                                            else
                                                a |= VT_CHAR_ATTR_BLINK;
                                        }
                                        if (pn[z] == 0 || pn[z] == 7) {
                                            if ( a & VT_CHAR_ATTR_REVERSE )
                                                a &= ~VT_CHAR_ATTR_REVERSE;
                                            else
                                                a |= VT_CHAR_ATTR_REVERSE;
                                        }
                                        line->vt_char_attrs[x] = a;
                                    }
                                      }
                            }
                        }
                        if (cursor_on_visible_page(VTERM)) {
                            VscrnIsDirty(VTERM);
                        }
                    }
                    break;
                case 'u':  /* DECRQTSR, DECCTR */
                    if (k >= 0) {
                        switch(pn[1]) {
                        case 0: /* Ignored */
                            break;
                        case 1: /* TODO: DECTSR */
                            if (ISVT420(tt_type_mode)) {
                                terminal_state_report();
                            }
                            break;
                        case 2: /* DECCTR */
                            if (k > 1 && (pn[2] == 1 || pn[2] == 2) &
                                    (ISVT525(tt_type_mode)
                                     || ISK95(tt_type_mode)) ) {
                                color_table_report(pn[2]);
                                     }
                            break;
                        }
                    }
                    break;
                case 'v':       /* DECCRA - Copy Rect Area */
                    if ( ISVT420( tt_type_mode) )
                    {
                        USHORT * data = NULL;
                        cell_video_attr_t *color_data = NULL;
                        USHORT * attr_data = NULL;
                        int w, h, x, y;
                        int src_page, dest_page, max_page;

                        /* Area to be copied:
                         * pn[1] - top-line border      default=1
                         * pn[2] - left-col border      default=1
                         * pn[3] - bottom-line border   default=last line
                         * pn[4] - right col border     default=last column
                         * pn[5] - page number          default=1
                         * Destination
                         * pn[6] - top-line border      default=1
                         * pn[7] - left-col border      default=1
                         * pn[8] - page number          default=1
                         *
                         * if pn[3] > pn[1] or pn[2] > pn[4] ignore
                         * coordinates are relative to DECOM setting
                         * not affected by page margins
                         * copy text, not attributes, destination attributes remain
                         * page becomes last available page if too large
                         * if destination is off page, clip off page data
                         */
                        if ( k < 1 || pn[1] == 0) pn[1] = 1;
                        if ( k < 2 || pn[2] == 0) pn[2] = 1;
                        if ( k < 3 || pn[3] == 0) pn[3] = VscrnGetHeight(VTERM)
                             -(tt_status[VTERM]?1:0);
                        if ( k < 4 || pn[4] == 0) pn[4] = VscrnGetWidth(VTERM);
                        if ( k < 5 || pn[5] == 0) pn[5] = 1;
                        if ( k < 6 || pn[6] == 0) pn[6] = 1;
                        if ( k < 7 || pn[7] == 0) pn[7] = 1;
                        if ( k < 8 || pn[8] == 0) pn[8] = 1;
                        k = 8;

                        if ( pn[3] < pn[1] || pn[4] < pn[2] )
                            break;

                        src_page = pn[5] - 1;
                        dest_page = pn[8] - 1;
                        max_page = term_max_page(VTERM);
                        if (src_page < 0) src_page = 0;
                        if (src_page > max_page) src_page = max_page;
                        if (dest_page < 0) dest_page = 0;
                        if (dest_page > max_page) dest_page = max_page;

                        if (on_alternate_buffer(VTERM)) {
                            src_page = dest_page = ALTERNATE_BUFFER_PAGE(VTERM);
                        }

                        if (relcursor) { /* DECOM enabled? */
                            int src_margintop, src_marginleft, dest_margintop, dest_marginleft;
                            src_margintop = vscrn_page_margin_top(VTERM, src_page);
                            src_marginleft = vscrn_page_margin_left(VTERM, src_page);
                            dest_margintop = vscrn_page_margin_top(VTERM, dest_page);
                            dest_marginleft = vscrn_page_margin_left(VTERM, dest_page);

                            pn[1] += src_margintop - 1;  /* Top border */
                            pn[2] += src_marginleft - 1; /* Left border */
                            pn[3] += src_margintop - 1;  /* Bottom border */
                            pn[4] += src_marginleft - 1; /* Right border */
                            /* pn[5] - source page */
                            pn[6] += dest_margintop - 1;  /* Top border */
                            pn[7] += dest_marginleft - 1; /* left border */
                            /* pn[7] - dest page */
                        }

                        w = pn[4] - pn[2] + 1;
                        h = pn[3] - pn[1] + 1;

                        data = malloc(sizeof(USHORT) * w * h);
                        if ( !data )	/* sizeof(viocell.c) */
                            break;

                        color_data = malloc(sizeof(cell_video_attr_t) * w * h);
                        if ( !color_data ) { /* sizeof(viocell.video_attr) */
                            if ( data ) free(data);
                            break;
                        }

                        attr_data = malloc(sizeof(USHORT) * w * h);
                        if ( !attr_data ) {/* sizeof(videoline.vt_char_attrs) */
                            if ( data ) free(data);
                            if (color_data) free(color_data);
                            break;
                        }

                        /* Read data from source page */
                        for ( y=0; y<h; y++ ) {
                            videoline * line = VscrnGetPageLineFromTop(VTERM, pn[1]+y-1, src_page);
                            for ( x=0; x<w; x++ ) {
                                data[y*w + x] = line->cells[pn[2]+x-1].c;
                                color_data[y*w + x] = line->cells[pn[2]+x-1].video_attr;
                                attr_data[y*w + x] = line->vt_char_attrs[pn[2]+x-1];
                            }
                        }

                        /* Write out to destination page */
                        for ( y=0; y<h; y++ ) {
                            videoline * line = VscrnGetPageLineFromTop(VTERM, pn[6]+y-1, dest_page);
                            for ( x=0; x<w && (pn[7]+x <= VscrnGetWidth(VTERM)); x++ ) {
                                line->cells[pn[7]+x-1].c = data[y*w + x];
                                line->cells[pn[7]+x-1].video_attr = color_data[y*w + x];
                                line->vt_char_attrs[pn[7]+x-1] = attr_data[y*w + x];
                            }
                        }
                        free(data);
                        free(color_data);
                        free(attr_data);
                        if (cursor_on_visible_page(VTERM)) {
                            VscrnIsDirty(VTERM);
                        }
                    }
                    break;

                case 'w':
                    if (ISVT320(tt_type_mode)) {  /* DECRQPSR - Request Presentation State Report */
                        if (k < 1 || pn[1] < 1 || pn[1] > 2)
                            pn[1] = 0;

                        presentation_state_report(pn[1]);
                    }
                    break;
                case 'x':       /* DECFRA - Fill Rect Area */
                    if ( ISVT420(tt_type_mode) ) {
                        /* pn[1] - fill char                 */
                        /* pn[2] - top-line border default=1 */
                        /* pn[3] - left-col border default=1 */
                        /* pn[4] - bot-line border default=Height */
                        /* pn[5] - Right border    default=Width */
                        if ( k < 5 || pn[5] > VscrnGetWidth(VTERM) ||
                             pn[5] < 1 )
                            pn[5] = VscrnGetWidth(VTERM);
                        if ( k < 4 || pn[4] > VscrnGetHeight(VTERM)
                             -(tt_status[VTERM]?1:0) || pn[4] < 1 )
                            pn[4] = VscrnGetHeight(VTERM)
                                -(tt_status[VTERM]?1:0);
                        if ( k < 3 || pn[3] < 1 )
                            pn[3] = 1 ;
                        if ( k < 2 || pn[2] < 1 )
                            pn[2] = 1 ;
                        if ( k < 1 )
                            pn[1] = SP ;

                        if (relcursor) {
                            /* Add top and left margins to the vertical and
                             * horizontal coordinates */
                            pn[2] += vscrn_c_page_margin_top(VTERM)-1; /* top */
                            pn[3] += vscrn_c_page_margin_left(VTERM)-1;/* lft */
                            pn[4] += vscrn_c_page_margin_top(VTERM)-1; /* bot */
                            pn[5] += vscrn_c_page_margin_left(VTERM)-1;/* rt */

                            if (pn[4] > vscrn_c_page_margin_bot(VTERM))
                                pn[4] = vscrn_c_page_margin_bot(VTERM);
                            if (pn[5] > vscrn_c_page_margin_right(VTERM))
                                pn[5] = vscrn_c_page_margin_right(VTERM);
                        }

                        if (pn[2] > pn[4]) break;
                        if (pn[3] > pn[5]) break;

                        /*  GL---------------------------   GR & BMP -------- */
                        if (pn[1] >= 32 && (pn[1] <= 126 || pn[1] >= 160)
                                && (pn[1] <= 255 || (tt_utf8 && pn[1] <= 65535))) {

                            int c = pn[1];
                            if ( !tt_utf8 ) {
                                /* Briefly pretend we're using an 8bit
                                 * connection so rtoxlat doesn't mask off the
                                 * 8th bit */
                                int x = cmdmsk;
                                cmdmsk = 255;

                                /* Translate from remote to local cset*/
                                c = rtolxlat(pn[1]);

                                /* Restore 7-bit mode if thats what we were
                                 * using before */
                                cmdmsk = x;
                            }

                            clrrect_escape( VTERM, pn[2], pn[3],
                                            pn[4], pn[5], c ) ;
                            if (cursor_on_visible_page(VTERM)) {
                                VscrnIsDirty(VTERM);
                            }
                        }
                    }
                    break;
                case 'z':       /* DECERA - Erase Rect Area */
                    if ( ISVT420(tt_type_mode) ) {
                        /* pn[1] - top-line border default=1 */
                        /* pn[2] - left-col border default=1 */
                        /* pn[3] - bot-line border default=Height */
                        /* pn[4] - Right border    default=Width */
                        if ( k < 4 || pn[4] > VscrnGetWidth(VTERM) ||
                             pn[4] < 1 )
                            pn[4] = VscrnGetWidth(VTERM);
                        if ( k < 3 || pn[3] > VscrnGetHeight(VTERM)
                             -(tt_status[VTERM]?1:0) || pn[3] < 1 )
                            pn[3] = VscrnGetHeight(VTERM)
                                -(tt_status[VTERM]?1:0);
                        if ( k < 2 || pn[2] < 1 )
                            pn[2] = 1 ;
                        if ( k < 1 || pn[1] < 1 )
                            pn[1] = 1 ;

                        if (relcursor) {
                            /* Add top and left margins to the vertical and
                             * horizontal coordinates */
                            pn[1] += vscrn_c_page_margin_top(VTERM)-1; /* top */
                            pn[2] += vscrn_c_page_margin_left(VTERM)-1;/* lft */
                            pn[3] += vscrn_c_page_margin_top(VTERM)-1; /* bot */
                            pn[4] += vscrn_c_page_margin_left(VTERM)-1;/* rt */

                            if (pn[3] > vscrn_c_page_margin_bot(VTERM))
                                pn[3] = vscrn_c_page_margin_bot(VTERM);
                            if (pn[4] > vscrn_c_page_margin_right(VTERM))
                                pn[4] = vscrn_c_page_margin_right(VTERM);
                        }

                        if (pn[1] > pn[3]) break;
                        if (pn[2] > pn[4]) break;

                        clrrect_escape( VTERM, pn[1], pn[2],
                                        pn[3], pn[4], NUL ) ;
                        if (cursor_on_visible_page(VTERM)) {
                            VscrnIsDirty(VTERM);
                        }
                    }
                    break;
                case '{':       /* DECSERA - Selective Erase Rect Area */
                    if ( ISVT420(tt_type_mode) ) {
                        /* pn[1] - top-line border default=1 */
                        /* pn[2] - left-col border default=1 */
                        /* pn[3] - bot-line border default=Height */
                        /* pn[4] - Right border    default=Width */
                        if ( k < 4 || pn[4] > VscrnGetWidth(VTERM) ||
                             pn[4] < 1 )
                            pn[4] = VscrnGetWidth(VTERM);
                        if ( k < 3 || pn[3] > VscrnGetHeight(VTERM)
                             -(tt_status[VTERM]?1:0) || pn[3] < 1 )
                            pn[3] = VscrnGetHeight(VTERM)
                                -(tt_status[VTERM]?1:0);
                        if ( k < 2 || pn[2] < 1 )
                            pn[2] = 1 ;
                        if ( k < 1 || pn[1] < 1 )
                            pn[1] = 1 ;

                        if (relcursor) {
                            /* Add top and left margins to the vertical and
                             * horizontal coordinates */
                            pn[1] += vscrn_c_page_margin_top(VTERM)-1; /* top */
                            pn[2] += vscrn_c_page_margin_left(VTERM)-1;/* lft */
                            pn[3] += vscrn_c_page_margin_top(VTERM)-1; /* bot */
                            pn[4] += vscrn_c_page_margin_left(VTERM)-1;/* rt */

                            if (pn[3] > vscrn_c_page_margin_bot(VTERM))
                                pn[3] = vscrn_c_page_margin_bot(VTERM);
                            if (pn[4] > vscrn_c_page_margin_right(VTERM))
                                pn[4] = vscrn_c_page_margin_right(VTERM);
                        }

                        if (pn[1] > pn[3]) break;
                        if (pn[2] > pn[4]) break;

                        selclrrect_escape( VTERM, pn[1], pn[2],
                                        pn[3], pn[4], SP ) ;
                        if (cursor_on_visible_page(VTERM)) {
                            VscrnIsDirty(VTERM);
                        }
                    }
                    break;
                }
                break;
            case ')': {
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch (achar) {

                    case '{': {        /* DECSTGLT - VT525  (and VT340?) */
                        if (ISVT525(tt_type_mode)) {
                            /* New mode is in pn[1] */
                            switch (pn[1]) {
                            case 0:   /* Monochrome */
                                if (decstglt != DECSTGLT_MONO) {
                                    decstglt = DECSTGLT_MONO;
                                    colorpalette = CK_PALETTE_VT525_M;
                                    reset_palette(colorpalette);
                                    VscrnIsDirty(VTERM);
                                }
                                break;
                            case 1:   /* Alternate Color */
                            case 2:   /* Alternate Color */
                                /* Show attributes as colors. The VT525 manual only
                                 * documents this behaviour for blink, bold, reverse
                                 * and underline. */
                                if (decstglt != DECSTGLT_ALTERNATE) {
                                    decstglt = DECSTGLT_ALTERNATE;
                                    colorpalette = CK_PALETTE_VT525_A;
                                    reset_palette(colorpalette);
                                    VscrnIsDirty(VTERM);
                                }
                                break;
                            case 3:   /* ANSI SGR */
                                if (decstglt != DECSTGLT_COLOR) {
                                    decstglt = DECSTGLT_COLOR;
                                    colorpalette = savedcolorpalette;
                                    reset_palette(colorpalette);
                                    VscrnIsDirty(VTERM);
                                }
                                break;
                            } /* pn[1] */
                        }
                        break;
                    } /* '}' */
                } /* achar */
                break;
            } /* ')' */
            case '*':
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch (achar) {
                case 'x':       /* DECSACE - Select Attribute Change Extent */
                    if ( ISVT420(tt_type_mode) )
                    {
                        /*
                         * 0 - DECCARA or DECRARA affect the stream of character
                               positions that begins with the first position specified
                               in the DECCARA or DECRARA command, and ends with the
                               second character position specified. (default)
                         * 1 - Same as 0.
                         * 2 - DECCARA or DECRARA affect all characters positions in
                               the rectangular area.  The DECCARA or DECRARA command
                               specifies the top-left and bottom-right corners.
                         */
                        if ( pn[1] == 0 || pn[1] == 1 )
                            decsace = FALSE;
                        else if ( pn[1] == 2 )
                            decsace = TRUE;
                    }
                    break;
                case 'y': {      /* DECRQCRA - Request Checksum of Rectangular Area */
                    if ( (ISVT420( tt_type_mode) || ISXTERM(tt_type_mode)) && tt_senddata) {
                        /* pn[1] - Request Id
                         * pn[2] - Page number
                         * pn[3] - top. Default=1
                         * pn[4] - left.
                         * pn[5] - bottom. Default=height of screen
                         * pn[6] - right. Width of screen
                         *
                         * If pn[2] is omitted (or 0), following parameters are ignored
                         * we're supposed to calculate the checksum for all pages in
                         * memory
                         *
                         * If pn[3-6] are omitted we calculate the checksum for the entire
                         * page.
                         *
                         * Constraints:
                         *   pn[4] < pn[6]
                         *   pn[3] < pn[5]
                         *
                         * Note: coordinates of the rectangular area are affected by
                         *       setting of origin mode
                         */
                        int checksum=0, pid=1;
                        int top, left, bot, right, page;
                        int row, col;
                        char buf[20];

                        if (k < 2) pn[2] = 0;
                        if (k < 3) pn[3] = 1;
                        if (k < 4) pn[4] = 1;
                        if (k < 5) pn[5] = VscrnGetHeight(VTERM) - (tt_status[VTERM] ? 1 : 0);
                        if (k < 6) pn[6] = VscrnGetWidth(VTERM);
                        k = 6;

                        pid = pn[1];
                        page = pn[2];

                        if (on_alternate_buffer(VTERM)) {
                            page = ALTERNATE_BUFFER_PAGE(VTERM);
                        }

                        top = pn[3];
                        left = pn[4];
                        bot = pn[5];
                        right = pn[6];

                        debug(F111, "DECRQCRA", "pid", pid);
						debug(F111, "DECRQCRA", "page", pn[2]);
                        debug(F111, "DECRQCRA", "init-top", pn[3]);
                        debug(F111, "DECRQCRA", "init-left", pn[4]);
                        debug(F111, "DECRQCRA", "init-bot", pn[5]);
                        debug(F111, "DECRQCRA", "init-right", pn[6]);

                        checksum = calculate_decrqcra_checksum(
                            top, left, bot, right, page, relcursor);

                        if (send_c1) {
                            sprintf(buf, "P%d!~%04X%c", pid, checksum, _ST8);
                        } else {
                            sprintf(buf, "P%d!~%04X\033\\", pid, checksum);
                        }
                        sendescseq(buf);
                    }

                    break;
                }
				case 'z': {
					if (ISVT420(tt_type_mode)) {	/* DECINVM - Invoke Macro */
						/* pn[1] is the macro to invoke. */
						vt_invoke_macro(pn[1]);
						break;
					} /* ISVT420 */
				} /* 'z' */
                break;

                case '|':      /* DECSNLS */
                    if (ISVT420(tt_type_mode)) {
                        set_term_height(pn[1]);
                    }
                    break;
				break;
                } /* '*' */
                break;
            case '`':
                {
                    /* Horizontal Position Absolute (HPA) */
                    /* moves active position to column pn[1] */
                    cursorhpa(pn[1]);
                    break;
                }
            case 'A':
                /* ANSI - Set Border Color */
                if ( ansiext ) {
                    if (ISANSI(tt_type_mode)) {
                        /* pn[1] contains new color */
                        if ( !sgrcolors )
                            break;
                        borderattribute = cell_video_attr_from_vio_attribute(sgrcols[pn[1]%8]);
                        setborder();
                    }
                    else if ( ISBA80(tt_type_mode) ) {
                        switch ( pn[1] ) {
                        case 0:
                            /* Dead Key Mode Off */
                            break;
                        case 1:
                            /* Dead Key Mode On */
                            break;
                        case 2:
                            /* Block Start */
                            break;
                        case 3:
                            /* Block End */
                            break;
                        }
                    }
                }
                else { /* CUU - Cursor up Pn lines */
                    if ( IS97801(tt_type_mode) ) {
                        /* ignored if outside scroll region */
                        if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                             wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                            break;
                    }
                    do {
                        cursorup(0);
                        if ( tt_type_mode != TT_ANSI &&
                             tt_type_mode != TT_SCOANSI &&
                             tt_type_mode != TT_AT386 )
                            wrapit = FALSE;
                        pn[1] = pn[1] - 1;
                    } while (!(pn[1] <= 0));
                }
                break;
            case 'a':
                /* HPR - Horizontal Position Relative */
                /* moves active position pn[1] characters */
                /* to the right. Only obeys margins if DECOM is set. */
                do {
                    cursorrightex(0, relcursor);
                    pn[1] = pn[1] - 1;
                } while (pn[1] > 0);
                break;
            case 'B':
                if ( ansiext ) {
                    /* ANSI - Set Beep Freq/Duration */
                    if ( ISANSI( tt_type_mode ) ) {
                        beepfreq = pn[1] ; /* ??? this isn't correct */
                        beeptime = pn[2] * 100 ;
                    }
                    else if ( ISBA80(tt_type_mode) ) {
                        switch ( pn[1] ) {
                        case 0:
                            /* Cursor Off */
                            cursorena[VTERM] = TRUE;
                            break;
                        case 1:
                            /* Cursor On */
                            cursorena[VTERM] = FALSE;
                            break;
                        case 2:
                            /* Alternate Cursor */
                            tt_cursor = TTC_BLOCK ;
                            setcursormode();
                            cursorena[VTERM] = TRUE ;
                            break;
                        case 3:
                            /* Normal Cursor */
                            tt_cursor = TTC_ULINE ;
                            setcursormode();
                            cursorena[VTERM] = TRUE ;
                            break;
                        }
                    }
                }
                else {  /* CUD - Cursor down pn lines */
                    if ( IS97801(tt_type_mode) ) {
                        /* ignored if outside scroll region */
                        if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                             wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                            break;
                    }
                    do {
                        cursordown(0);
                        if ( !ISANSI( tt_type_mode ) ||
                             ISLINUX(tt_type_mode))
                            wrapit = FALSE;
                        pn[1] = pn[1] - 1;
                    } while (!(pn[1] <= 0));
                }
                break;
            case 'b':
                /* QANSI - Repeat previous character Pn times */
                if ( ISQANSI(tt_type_mode) || ISXTERM(tt_type_mode) || ISK95(tt_type_mode) ) {
                    while ( pn[1] ) {
                        wrtch(prevchar);
                        pn[1] = pn[1] - 1;
                    }
                } else if ( ISSCO(tt_type_mode) ||
                            ISAAA(tt_type_mode)) {
                    /* HPR - Horizontal Position Relative */
                    while ( pn[2] ) {
                        wrtch(pn[1]);
                        pn[2] = pn[2] - 1;
                    }
                }
                break;
            case 'C':
                if ( ISBA80(tt_type_mode) && ansiext ) {
                    /* Close Virtual Window */
                    /* close the current virtual window */
                }
                /* ANSI - Set Cursor Height */
                if ( ISANSI( tt_type_mode ) &&
                     ansiext ) {
                    debug(F111,"ANSI-SetCursor","start",pn[1]);
                    debug(F111,"ANSI-SetCursor","end",pn[2]);
                    if ( pn[1] > pn[2] ) {
                        cursorena[VTERM] = FALSE ;
                    }
                    else {
                        if ( pn[2]-pn[1] <= 1 )
                            tt_cursor = TTC_ULINE ;
                        else if ( pn[2]-pn[1] < 10 )
                            tt_cursor = TTC_HALF ;
                        else
                            tt_cursor = TTC_BLOCK ;
                        setcursormode();
                        cursorena[VTERM] = TRUE ;
                    }
                }
                else {
                    /* CUF - Cursor right pn chars */
                    bool lcf = wrapit;
                    do {
                        cursorright(0);
                        pn[1] = pn[1] - 1;
                    } while (pn[1] > 0);

                    if (tt_type == TT_VT100 || tt_type == TT_VT102) {
                        /* The VT10x and only the VT10x does not reset the LCF
                         * on CUF. The VT220 and VT520 when emulating a VT100
                         * do. So restore the LCF from the earlier backup  */
                        wrapit = lcf;
                    }
                }
                break;
            case 'c':
                if ( zdsext && ISVT220(tt_type) ) {
                    /* Secondary Device Attributes Report Request */
                    if (pn[1] == 0) {
                        /* Switch on tt_type (users selected terminal type)
                         * rather than tt_type_mode (host selected emulation via
                         * DECTME, DECSCL, etc) as setting a VT to emulate
                         * something else doesn't seem to change its secondary
                         * DA response. */
                        switch (tt_type) {
                            case TT_VT220:
                            case TT_VT220PC:
                                sendescseq("[>1;0;0c");     /* VT220 */
                                break;
                            case TT_K95:
                                /* The K95 terminal type isn't fully
                                 * VT420-compatible yet, but it isn't far off
                                 * and importantly it uses the same character
                                 * cell size for soft-fonts. DEC didn't provide
                                 * any way to identify character cell size
                                 * directly so this is about the only thing the
                                 * host can rely on. */
                                sendescseq("[>41;0;0c");    /* VT420 */
                                break;
                            case TT_VT320:
                            case TT_VT320PC:
                            case TT_WY370:    /* Responds as a VT320 */
                            default:
                                sendescseq("[>24;0;0c");    /* VT320 */
                                break;
#ifdef COMMENT
                            /* None of these emulations are implemented yet */
                            case TT_VT22Z:
                            case TT_VT22ZPC:
                                /* This is what my VT220Z reports. The meaning
                                 * of option 2 is currently unknown, but regular
                                 * VT220s apparently don't report it so it is
                                 * possibly significant for the VT220Z. */
                                sendescseq("[>1;31;2c");
                                break;
                            case TT_DECTERM:
                                sendescseq("[>28;0;0c");    /* DECterm */
                                break;
                            case TT_VTSTAR:
                                sendescseq("[>66;0;0c");    /* Multia VTStar */
                                break;
                            case TT_VT420:
                            case TT_VT420PC:
                                /* TODO: Maybe TT_VT420PC should report option 1
                                 *       (PC Keyboard)? */
                                sendescseq("[>41;0;0c");    /* VT420 */
                                break;
                            case TT_VT510:
                            case TT_VT510PC:
                                sendescseq("[>61;0;0c");    /* VT510 */
                                break;
                            case TT_VT520:
                            case TT_VT520PC:
                                sendescseq("[>64;0;0c");    /* VT520 */
                                break;
                            case TT_VT525:
                            case TT_VT525PC:
                                sendescseq("[>65;0;0c");    /* VT520 */
                                break;
#endif
                        }
                    }
                }
                else if ( ansiext && ISVT220(tt_type) ) {
                    /* Tertiary Device Attributes Report Request */
                    if (pn[1] == 0) {
                        char DECRPTUI[24] ;
                        sprintf(DECRPTUI,"P!|00000000%c\\",ESC);
                        sendescseq(DECRPTUI);
                    }
                }
                else if ( IS97801(tt_type_mode) ) {
                    /* Reset to Initial State */
                    if ( debses )
                        break;
                    doreset(1);
                }
                else if ( ansiext && ISSCO(tt_type_mode) ||
                          ISANSI( tt_type_mode ) ) {
                    /* Set Cursor Type */
                    /* pn[1] = 0 - underline */
                    /* pn[1] = 1 - block     */
                    /* pn[1] = 2 - no cursor */
                    debug(F111,"CSI c","SetCursorType",pn[1]);
                    switch ( pn[1] ) {
                    case 0:
                        tt_cursor = TTC_ULINE ;
                        cursorena[VTERM] = TRUE;
                        break;
                    case 1:
                        tt_cursor = TTC_BLOCK ;
                        cursorena[VTERM] = TRUE ;
                        break;
                    case 2:
                        cursorena[VTERM] = FALSE ;
                        break;
                    }
                    setcursormode() ;
                }
                else if ( private && ISLINUX(tt_type_mode) ) {
                    /* Set Cursor Type */
#ifdef COMMENT
  VGA-softcursor.txt, from the 2.2 kernel

  Software cursor for VGA    by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
  =======================    and Martin Mares <mj@atrey.karlin.mff.cuni.cz>

     Linux now has some ability to manipulate cursor appearance. Normally, you
  can set the size of hardware cursor (and also work around some ugly bugs in
  those miserable Trident cards--see #define TRIDENT_GLITCH in drivers/video/
  vgacon.c). You can now play a few new tricks:  you can make your cursor look
  like a non-blinking red block, make it inverse background of the character it's
  over or to highlight that character and still choose whether the original
  hardware cursor should remain visible or not.  There may be other things I have
  never thought of.

     The cursor appearance is controlled by a "<ESC>[?1;2;3c" escape sequence
  where 1, 2 and 3 are parameters described below. If you omit any of them,
  they will default to zeroes.

     Parameter 1 specifies cursor size (0=default, 1=invisible, 2=underline, ...,
  8=full block) + 16 if you want the software cursor to be applied + 32 if you
  want to always change the background color + 64 if you dislike having the
  background the same as the foreground.  Highlights are ignored for the last two
  flags.

     The second parameter selects character attribute bits you want to change
  (by simply XORing them with the value of this parameter). On standard VGA,
  the high four bits specify background and the low four the foreground. In both
  groups, low three bits set color (as in normal color codes used by the console)
  and the most significant one turns on highlight (or sometimes blinking--it
  depends on the configuration of your VGA).

     The third parameter consists of character attribute bits you want to set.
  Bit setting takes place before bit toggling, so you can simply clear a bit by
  including it in both the set mask and the toggle mask.

  Examples:
  =========

  To get normal blinking underline, use: echo -e '\033[?2c'
  To get blinking block, use:            echo -e '\033[?6c'
  To get red non-blinking block, use:    echo -e '\033[?17;0;64c'
#endif /* COMMENT */
                    debug(F111,"CSI ? c","SetCursorType pn[1]",pn[1]);
                    debug(F111,"CSI ? c","SetCursorType pn[2]",pn[2]);
                    debug(F111,"CSI ? c","SetCursorType pn[3]",pn[3]);
                    switch ( pn[1] & 0x0F ) {
                    case 0:
                    case 2:
                        tt_cursor = TTC_ULINE ;
                        cursorena[VTERM] = TRUE;
                        break;
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                        tt_cursor = TTC_HALF ;
                        cursorena[VTERM] = TRUE ;
                        break;
                    case 8:
                        tt_cursor = TTC_BLOCK ;
                        cursorena[VTERM] = TRUE ;
                        break;
                    case 1:
                        cursorena[VTERM] = FALSE ;
                        break;
                    }
                    setcursormode() ;
                    break;
                } else { /* DA - Device Attributes */
                    if (pn[1] == 0)
                        if (tt_type >= 0 &&
                             tt_type <= max_tt) {
                            if (ISK95(tt_type) && tt_clipboard_write >= CLIPBOARD_ALLOW) {
                                /* If writing to the clipboard via OSC-52 is
                                 * enabled, indicate this by appending extension
                                 * 52 to the DA1 response (Windows Terminal) */
                                char da1buf[100];
                                memset(da1buf, 0, sizeof(da1buf));
                                strcat(da1buf, tt_info[tt_type].x_id);
                                da1buf[strlen(da1buf)-1] = '\0';
                                strcat(da1buf, ";52c");
                                sendescseq(da1buf);
                            } else {
                                sendescseq(tt_info[tt_type].x_id);
                            }
                        }
                    }
                    break;
            case 'D':
                /* ANSI - Turn on/off Background Intensity */
                if ( ISANSI( tt_type_mode ) &&
                     ansiext ) {
                    if ( !pn[1] && !bgi ||
                         pn[1] && bgi ) {
                        attribute = cell_video_attr_with_bg_intensity_set(attribute);
                        defaultattribute = cell_video_attr_with_bg_intensity_set(defaultattribute);
                    }
                    else
                    {
                        attribute = cell_video_attr_with_bg_intensity_unset(attribute);
                        defaultattribute = cell_video_attr_with_bg_intensity_unset(defaultattribute);
                    }
                }
                else  /* CUB - Cursor Left pn characters */
                    do {
                        cursorleft(0);
                        pn[1] = pn[1] - 1;
                    } while (pn[1] > 0);
                break;
            case 'd':
                /* VPA - Vertical Position Absolute */
                /* moves active position to row pn[1] */
                if (relcursor) pn[1] += vscrn_c_page_margin_top(VTERM) - 1;
                if ( decsasd == SASD_TERMINAL )
                    lgotoxy( VTERM, wherex[VTERM], pn[1] ) ;
                break;
            case 'E':
                if ( ISBA80(tt_type_mode) && ansiext ) {
                    /* Window Status Request */
                    char buf[64];
                    sprintf(buf,"%c[=D%3d:%3d;001:001;Lohn    D",
                             27,VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0),
                             VscrnGetWidth(VTERM));
                        ttol(buf,strlen(buf));
                }
                /* ANSI - TRUE BLINK vs Bold Background Intensity */
                if ( ISANSI( tt_type_mode ) &&
                     ansiext ) {
                    if ( !pn[1] )
                    {
                        /* use TRUE BLINK - default */
                        trueblink = TRUE ;
                    }
                    else
                    {
                        /* use Bold Background Intensity */
                        trueblink = FALSE ;
                    }
                }
                else {
                    /* CNL - Cursor next line */
                    /* moves active position pn[1] rows down */
                    if (pn[1] < 1) pn[1] = 1;

                    if (pn[1] + wherey[VTERM] >= vscrn_c_page_margin_bot(VTERM))
                        pn[1] = vscrn_c_page_margin_bot(VTERM) - wherey[VTERM];

                    cursornextline(FALSE, pn[1]);
                }
                break;
            case 'e':
                /* VPR - Vertical Position Relative */
                /* moves active position pn[1] rows down.
				 * Only obeys margins if DECOM is set */
                do {
                    cursordownex(0,relcursor);
                    pn[1] = pn[1] - 1;
                } while (pn[1] > 0);
                break;
            case 'F':
                if ( ISBA80(tt_type_mode) && ansiext ) {
                    /* Fetch virtual window from the background */
                }
                /* ANSI - Set Normal Foreground Color */
                if (( ISANSI( tt_type_mode ) ||
                      ISQANSI(tt_type_mode)) &&
                     ansiext ) {
                    /* pn[1] contains new color */
                    l = pn[1];
                    if (decscnm   /* If the display is in reverse video mode */
#ifdef COMMENT
                         && !attrib.reversed ||
                         !decscnm && attrib.reversed
#endif
                         ) {
                         /* The original code did this:
                         i = (defaultattribute & 0xF0);
                         attribute = defaultattribute = (i | (l << 4));
                          * The first line wipes out the foreground colour,
                          * while the second-line ORs the new foreground colour
                          * with the existing background colour, and sets the
                          * result as the new background colour. The resulting
                          * background colour is *not* guaranteed to be what was
                          * supplied as the new foreground colour in pn[1]. This
                          * seems like very odd behaviour for "Set Normal
                          * Foreground Color".
                          *
                          * The replacement code instead just sets the supplied
                          * color as the new background color preserving the current
                          * foreground color, the opposite of the non-reverse-video
                          * operation. This seems more likely to be correct.
                          */

                         attribute = defaultattribute = cell_video_attr_set_bg_color(defaultattribute, l);
                    }
                    else {
                        attribute = defaultattribute = cell_video_attr_set_fg_color(defaultattribute, l);
                    }
                }
                else {
                    /* CPL - Cursor Previous Line */
                    /* moves active position pn[1] rows up */
                    /* in the first column */
                    if (pn[1] == 0) pn[1] = 1;
                    cursorprevline(pn[1]);
                    /*
                    do {
                        cursorprevline(pn[1]);
                        pn[1] = pn[1] - 1;
                    } while (pn[1] > 0);*/
                }
                break;
            case 'G':
                /* ANSI - Set Normal Background Color */
                if ( ansiext &&
                     (ISANSI( tt_type_mode ) || ISQANSI(tt_type_mode)) ) {
                    /* pn[1] contains new color */
                    l = pn[1];
                    if (!decscnm
#ifdef COMMENT
                         && !attrib.reversed ||
                         decscnm && attrib.reversed
#endif
                         ) {
                        attribute = defaultattribute = cell_video_attr_set_bg_color(defaultattribute, l);
                    }
                    else {
                        /* Previously the above was:
                               = ((defaultattribute & 0x0F) | (l << 4));
                           While below was:
                               = ((defaultattribute & 0x0F) | l);
                           Which seems a lot like a bug. 0x0F clears the background,
                           while 0xF0 clears the foreground, and you <<4 to set the
                           background. The behaviour below (for 16 colour builds)
                           should now be correct.
                         */
                        attribute = defaultattribute = cell_video_attr_set_fg_color(defaultattribute, l);
                    }
                }
                else {
                    /* CHA - Cursor Horizontal Absolute */
                    if ( ISHFT(tt_type_mode) ||
                         ISLINUX(tt_type_mode) ||
                         ISQANSI(tt_type_mode) ||
                         ISANSI(tt_type_mode) ||
                         ISVT520(tt_type_mode) ||
                         ISXTERM(tt_type_mode)) {
                        cursorhpa(pn[1]);
                    }
                }
                break;
            case 'H':
                /* ANSI - Set Reverse Foreground Color */
                if ( ISANSI( tt_type_mode ) &&
                     ansiext ) {
                    /* pn[1] contains new color */
                    l = pn[1];
					reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
                    break;
                }
                /* 'H' is also CUP - Direct cursor address for */
                /* !ansiext, so don't put a break here   */
            case 'f': { /* HVP - Direct cursor address */
                bool lcf = wrapit;
                if ( IS97801(tt_type_mode) && decsasd == SASD_STATUS )
                    setdecsasd(SASD_TERMINAL);

                if (pn[1] == 0)
                    pn[1] = 1;
                if (relcursor)
                {
                    pn[1] += vscrn_c_page_margin_top(VTERM) - 1;
                    if (pn[1] > vscrn_c_page_margin_bot(VTERM))
                    {
                        pn[1] = vscrn_c_page_margin_bot(VTERM);
                    }
                }
                if (pn[1] > VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0))
                    pn[1] = VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0);
                if (pn[2] == 0)
                    pn[2] = 1;
                if (relcursor)
                    pn[2] += vscrn_c_page_margin_left(VTERM) - 1;

                {
                    /* Ensure coordinates are to the left of screen right, or
                     * if DECOM is set, the right margin */
                    int r = (relcursor ? vscrn_c_page_margin_right(VTERM)
                                       : VscrnGetWidth(VTERM));

                    /* if this line is double width, then its half length */
                    if (isdoublewidth(pn[1])) {
                        r = r / 2;
                    }

                    if (pn[2] > r) pn[2] = r;
                }

                wrapit = FALSE;

                /* SNI 97801 - If the cursor is addressed to the */
                /* status line when SSDT_HOST_WRITABLE, we must  */
                /* enter SASD_STATUS mode                        */
                if ( IS97801(tt_type_mode) ) {
                    if ( pn[1] == VscrnGetHeight(VTERM) &&
                         decsasd != SASD_STATUS ) {
                        if ( decssdt == SSDT_INDICATOR )
                            setdecssdt(SSDT_HOST_WRITABLE);
                        setdecsasd(SASD_STATUS);
                         }
                }

                if ( decsasd == SASD_STATUS )
                    lgotoxy( VSTATUS, pn[2], 1 );
                else
                    lgotoxy(VTERM, pn[2], pn[1]);

                if (tt_type == TT_VT100 || tt_type == TT_VT102) {
                    /* The VT10x and only the VT10x does not reset the
                     * LCF on CUP or HVP. The VT220 and VT520 when emulating a
                     * VT100 do. So restore the LCF from a backup taken earlier.
                     */
                    wrapit = lcf;
                }
            }
            break;
            case 'I':
                if ( ansiext && private ) {
                    if ( ISBA80(tt_type_mode) ) {
                        /* Screen Saver Off */
                    }
                }
                else if ( ansiext ) {
                    if ( ISBA80(tt_type_mode) ) {
                        /* Input */
                    }
                    /* ANSI - Set Reverse Background Color */
                    if ( ISANSI( tt_type_mode ) )
                    {
                        /* pn[1] contains new color */
                        l = pn[1];
                        reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
                    }
                }
                else {
                    /* CHT - Cursor Horizontal Tab */
                    if ( k < 1 || pn[1] < 1)
                        pn[1] = 1;
                    cursortab(pn[1]);
                }
                break;
            case 'g':
                /* ANSI - Display Graphic Character */
                if ( ISSCO(tt_type_mode) && !scoBCS2 ||
                     ISANSI( tt_type_mode ) &&
                     ansiext ) {
                    /* pn[1] contains a graphic Character
                    to display */
                    cell_video_attr_t a = attribute ;
                    int eight = sco8bit ;
                    int c = crm ;
                    struct _vtG * g = GR ;

                    attribute = graphicattribute ;
                    sco8bit = FALSE ;
                    crm = TRUE;
                    GR = &G[2];

                    wrtch( pn[1] ) ;

                    attribute = a ;
                    sco8bit = eight ;
                    crm = c;
                    GR = g;
                }
                else {
                    /* TBC - Tabulation Clear */
                    /* VT terminals only support 0 and 3 */
                    /* HFT (begin) */
                    /*  0 - clear horizontal tab stop at active position */
                    /*  1 - vertical tab at line indicated by cursor     */
                    /*  2 - horizontal tabs on line                      */
                    /*  3 - all horizontal tabs                          */
                    /*  4 - all vertical tabs                            */
                    /* HFT (end)                                         */
                    /* SCO BCS2 mode supports this functionality */
                    if (pn[1] == 3 || 
                        (pn[1] == 2 && !ISVT100(tt_type_mode)))
                    {
                        /* clear all tabs */
                        for (j = 1; j <=MAXTERMCOL; ++j)
                            htab[j] = '0';
                    } else if (pn[1] == 0) {
                        /* clear tab at current position */
                        htab[wherex[VTERM]] = '0';
                    }
                }
                break;
            case 'h':   /* Set Mode */
                for (j = 1; j <= k; ++j) {
                    if (private) {
                        switch (pn[j]) {        /* Field specs */
                        case 1: /* DECCKM  */
                            tt_arrow = TTK_APPL;
                            break;
                        case 2:
                            /* DECANM : ANSI/VT52 */
                            /* XTERM - Designate US_ASCII into G0-G3 */
                            if ( ISH19(tt_type) ) {
                                tt_type_mode = tt_type ;
                                vt52graphics = FALSE;
                            }
                            else if ( decsasd == SASD_TERMINAL ){
                                if ( ISVT52(tt_type_mode) ) {
                                    tt_type_mode = tt_type_vt52 ;
                                    vt52graphics = FALSE;
                                    ipadl25();
                                }
                            }
                            break;
                        case 3: /* DECCOLM = 132 Columns */
                            RequestScreenMutex(SEM_INDEFINITE_WAIT);
                            killcursor(VTERM);
                            deccolm = TRUE;
                            Set132Cols(VTERM);
                            set_declrmm(FALSE);
                            naws();
                            setborder();
                            newcursor(VTERM);
                            clrscreen(VTERM,SP);
                            lgotoxy(VTERM,1,1);       /* and home the cursor */
                            ipadl25();
                            ReleaseScreenMutex();
                            break;
                        case 4: /* DECSCLM - Smooth scroll */
                            SmoothScroll();
                            break;
                        case 5: /* DECSCNM - Reverse screen */
                            if (decscnm) /* Already reverse */
                                break;
                            else {
                                flipscreen(VTERM);
                                VscrnIsDirty(VTERM) ;
                            }
                            break;
                        case 6: /* DECOM - Relative origin */
                            relcursor = TRUE;
                            home_cursor(vmode);
                            break;
                        case 7: /* DECAWM - Auto Wrap mode */
                            tt_wrap = TRUE;
                            break;
                        case 8: /* DECARM - Autorepeat */
#ifdef NT
                            tt_autorepeat = TRUE;
#endif /* NT */
                            break;
                        case 9: /* DECINLM - Interlace. VT1xx only. */
                            /* XTERM - Send Mouse X & Y on button press */
#ifdef OS2MOUSE
                            if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {
                                /* The linux console terminal, as well as many
                                 * other terminal emulators, implement XTERM
                                 * mouse tracking */

                                debug(F100, "X10 mouse tracking now ON", "", 0);
                                mouse_reporting_mode |= MOUSEREPORTING_X10;
                            }
#endif
                            break;
                        case 10:        /* DECEDM - Block Mode On */
                            if (ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                /* Toolbar on (rxvt) */
#ifdef KUI
#ifndef NOTOOLBAR
                                KuiSetProperty(KUI_GUI_TOOLBAR_VIS, (intptr_t)1, 0L);
#endif
#endif
                            }
                            break;
						case 12:  		/* AT&T 610/xterm - Blinking cursor on */
							tt_cursor_blink = 1;
							break;
                        case 18:  /* DECPFF - Print Form Feed */
                            xprintff = TRUE;
                            break;
                        case 19:        /* DECPEX - Printer extent */
                            printregion = FALSE; /* Full screen */
                            break;
                        case 25:   /* DECTCEM - Cursor On */
                            cursorena[VTERM] = TRUE;
                            break;
                        case 34:    /* DECRLM - Right to Left Mode */
                            debug(F111,"VT","DECRLM - Right to Left Mode",1);
                            break;
                        case 35: /* DECHEBM */
                            /* Enter Hebrew keyboard mode */
                            tt_kb_mode = KBM_HE ;
                            break;
                        case 36:    /* DECHEM - Hebrew Encoding Mode */
                            debug(F111,"VT","DECHEM - Hebrew Encoding Mode",1);
                            break;
                        case 38: /* DECTEK */
                            /* Enter Tektronix 4010/4014 mode */
                            settekmode();
                            break;
                        case 40: /* XTERM - Allow 80 - 132 Mode */
                            break;
                        case 41: /* XTERM - more(1) fix */
                            break;
                        case 42: { /* DECNRCM */
                            /* Use 7-bit NRC */

                            decnrcm = TRUE ;
#ifdef COMMENT
                            if ( G[0].national )
                            {
                                for ( i = 1 ; i < 4 ; i++ ) {
                                    G[i].designation =
                                        G[0].def_designation ;
                                    G[i].size = G[0].def_size ;
                                    G[i].c1   = G[0].def_c1 ;
                                    G[i].national = G[0].national;
                                    G[i].rtoi = xl_u[G[0].def_designation];
                                    if ( ck_isunicode() ) {
                                        G[i].itol = NULL ;
                                        G[i].ltoi = NULL ;
                                    }
                                    else {
                                        G[i].itol = xl_tx[tcsl] ;
                                        G[i].ltoi = xl_u[tcsl] ;
                                    }
                                    G[i].itor = xl_tx[G[0].def_designation] ;
                                }
                            }
                            else {
                                for ( i = 1 ; i < 4 ; i++ ) {
                                    G[i].designation = TX_ASCII;
                                    G[i].size = cs94 ;
                                    G[i].c1 = TRUE ;
                                    G[i].national = CSisNRC(G[i].designation);
                                    G[i].rtoi = xl_u[TX_ASCII];
                                    if ( ck_isunicode() ) {
                                        G[i].itol = NULL ;
                                        G[i].ltoi = NULL ;
                                    }
                                    else {
                                        G[i].itol = xl_tx[tcsl] ;
                                        G[i].ltoi = xl_u[tcsl] ;
                                    }
                                    G[i].itor = xl_tx[TX_ASCII];
                                }
                            }
#else /* COMMENT */
                            for ( i = 1 ; i < 4 ; i++ ) {
                                G[i].designation = dec_nrc;
                                G[i].size = cs94 ;
                                G[i].c1 = TRUE ;
                                G[i].national = CSisNRC(dec_nrc);
                                G[i].rtoi = xl_u[dec_nrc];
                                if ( ck_isunicode() ) {
                                    G[i].itol = NULL ;
                                    G[i].ltoi = NULL ;
                                }
                                else {
                                    G[i].itol = xl_tx[tcsl] ;
                                    G[i].ltoi = xl_u[tcsl] ;
                                }
                                G[i].itor = xl_tx[dec_nrc];
                            }
#endif /* COMMENT */
                        }
                            break;
                        case 43: /* DECGEPM */
                            /* Graphics Expanded Print mode */
                            break;
                        case 44: /* DECGPCM */
                            /* Graphics Print Color mode */
                            /* XTERM - Turn on Margin Bell */
                            break;
                        case 45: /* DECGPCS */
                            /* Graphics Print Color syntax = RGB */
                            /* XTERM - Reverse-wraparound mode */
                            break;
                        case 46: /* DECGPBM */
                            /* Graphics Print Background mode */
                            /* XTERM - Start Logging */
                            break;
                        case 47: /* DECGRCM */
                            /* Graphics Rotated Print mode */
                            /* XTERM - Use Alternate Screen Buffer */
                            break;
                        case 53: /* DEC131TM */
                            /* VT131 Transmit */
                            break;
                        case 60: /* DECHCCM */
                            /* Horizontal cursor coupling */
                            break;
                        case 61: /* DECVCCM */
                            /* Vertical cursor coupling */
                            break;
                        case 64: /* DECPCCM */
                            /* Page cursor coupling */
                            if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
							    vscrn[VTERM].page_cursor_coupling = TRUE;
							    vscrn[vmode].view_page = vscrn[vmode].cursor.p;
                            }
                            break;
                        case 66: /* DECNKM */
                            /* Numeric Keyboard - Application */
                            tt_keypad = TTK_APPL ;
                            break;
                        case 67: /* DECBKM */
                            /* Backarrow key sends BS */
                            if ( !savdecbkm )
                                savdecbkm = keymap[KEY_SCAN | 8];
                            keymap[KEY_SCAN | 8] = BS ;
                            break;
                        case 68: /* DECKBUM */
                            /* Keyboard Usage - Data Processing */
                            deckbum = 1;
                            break;
						case 69: /* DECLRMM aka DECVSSM */
                            if (ISVT420(tt_type_mode) || ISK95(tt_type_mode) ||
                                ISXTERM(tt_type_mode))
                            {
                                set_declrmm(TRUE);
                            }
							break;
                        case 73: /* DECXRLM */
                            /* Transmit rate limiting */
                            break;
                        case 80:        /* WY161 - 161-column mode */
                            if ( ISWY370(tt_type_mode) )
                            {
                                tt_szchng[VTERM] = 1 ;
                                tt_cols[VTERM] = 161 ;
                                VscrnInit( VTERM ) ;  /* Height set here */
                                naws();
                            }
                            break;
                            case 83:    /* WY52 - 52 line mode */
                            if ( ISWY370(tt_type_mode)) {
                                set_term_height(52);
                            }
                            break;
                        case 84:        /* WYENAT */
                            if ( ISWY370(tt_type_mode) )
                                /* Enable separate assignment of */
                                /* attributes (SGR) to erasable  */
                                /* and nonerasable characters    */
                                ;
                            break;
                        case 85:        /* WYREPL */
                            if ( ISWY370(tt_type_mode) )
                                /* Set replacement character to */
                                /* current character background */
                                /* color */
                                ;
                            break;
                        case 95:       /* DECNCSM */
                            if (ISVT520(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                decncsm = TRUE;
                            }
                            break;
                        case 114:      /* DECATCUM */
                            decatcum = TRUE;
                            break;
                        case 115:      /* DECATCBM */
                            decatcbm = TRUE;
                            break;
                        case 116: /* DECBBSM */
                            break;
                        case 117: /* DECECM */
                            /* On - erase with default/normal colour,
                             * Off - erase with current attribute colour */
                            if (ISVT525(tt_type_mode)) {
                                erasemode = 1;
                            }
                            break;
                        case 1000:
                            /* XTERM - Send Mouse X&Y on button press and release */
#ifdef OS2MOUSE
                            debug(F100, "X11 (xterm) mouse tracking now ON", "", 0);
                            mouse_reporting_mode |= MOUSEREPORTING_X11;
#endif
                            break;
                        case 1001:
                            /* XTERM - Use Hilite Mouse Tracking */
                            break;
                        case 1002:
                            /* XTERM - Cell Motion Mouse Tracking */
#ifdef OS2MOUSE
                            debug(F100, "Button-event mouse tracking now ON", "", 0);
                            mouse_reporting_mode |= MOUSEREPORTING_BTNEVENT;
#endif
                            break;
                        case 1003:
                            /* XTERM - All Motion Mouse Tracking */
#ifdef OS2MOUSE
                            debug(F100, "Any-event mouse tracking now ON", "", 0);
                            mouse_reporting_mode |= MOUSEREPORTING_ANYEVENT;
#endif
                            break;
                        case 1004:
                            /* XTERM - Send FocusIn/FocusOut events*/
#ifdef KUI
                            transmit_focus_change = TRUE;
#endif /* KUI */
                            break;
                        case 1005:
                            /* XTERM - Enable UTF-8 Mouse Mode */
                            break;
                        case 1006:
                            /* XTERM - Enable SGR Mouse Mode */
#ifdef OS2MOUSE
                           debug(F100, "SGR mouse tracking now ON", "", 0);
                           mouse_reporting_mode |= MOUSEREPORTING_SGR;
#endif
                            break;
                        case 1007:
                            /* XTERM - Enable Alternate Scroll Mode */
                            break;
                        case 1010:
                            /* RXVT - Scroll to bottom on tty output */
                            break;
                        case 1011:
                            /* RXVT - Scroll to bottom on key press */
                            tt_rkeys[VTERM] = TTRK_RST;
                            break;
                        case 1015:
                            /* URXVT - Enable URXVT Mosue Mode */
#ifdef OS2MOUSE
                           debug(F100, "URXVT mouse tracking now ON", "", 0);
                           mouse_reporting_mode |= MOUSEREPORTING_URXVT;
#endif
                            break;
						case 1034:  /* xterm - Interpret "meta" key - sets 8th bit */
							tt_kb_mode = KBM_MM;
							ipadl25();  /* Update the status line */
							break;
						case 1036:  /* xterm - send esc when Meta modifies a key */
							tt_kb_mode = KBM_ME;
							ipadl25();;  /* Update the status line */
							break;
                        case 1042:    /* xterm - enable urgency window hint on bell */
#ifdef KUI
                            tt_bell_flash = TRUE;
#endif /* KUI */
                            break;
                        case 1043:    /* xterm - raise window hint on bell */
#ifdef KUI
                            tt_bell_raise = TRUE;
#endif /* KUI */
                            break;
                        case 1046:    /* xterm - allow switching to alternate buffer */
                            if (ISK95(tt_type) || ISXTERM(tt_type)) {
                                set_alternate_buffer_enabled(vmode, TRUE);
                            }
                            break;
                        case 1047:    /* xterm - go to alternate screen */
                            if ((ISK95(tt_type) || ISXTERM(tt_type)) && vscrn[vmode].allow_alt_buf) {
                                to_alternate_buffer(vmode);
                            }
                            break;
                        case 1048:    /* xterm - save cursor as in DECSC */
                            if (ISK95(tt_type) || ISXTERM(tt_type)) {
                                savecurpos(vmode, 1);
                            }
                            break;
                        case 1049:    /* xterm - to alt buffer, clearing and saving ? */
                            if ((ISK95(tt_type) || ISXTERM(tt_type)) && vscrn[vmode].allow_alt_buf) {
                                savecurpos(vmode, 1);
                                to_alternate_buffer(vmode);
                                clrpage(vmode,
                                        ' ',
                                        ALTERNATE_BUFFER_PAGE(vmode));
                            }
                            break;
                        case 2004:
                            /* xterm - Set Bracketed Paste Mode */
                            bracketed_paste[vmode] = TRUE;
                            break;
                        case 2026:
#ifdef KUI
                            if (ISK95(tt_type_mode)) {
                                /* various - Synchronized Output */
                                if (!tt_sync_output) {
                                    /* Don't alow the timeout to be suppressed by
                                     * spamming this set mode. */
                                    tt_sync_output_timeout = SYNC_OUTPUT_TIMEOUT;
                                }
                                tt_sync_output = TRUE;
                            }
#endif /* KUI */
                            break;
                        default:
                            break;
                        }
                    } else if ( zdsext ) {
                        switch (pn[j]) {
                        /* Zenith/Heath values */
                        case 1: /* Enable 25th line */
                            if ( !tt_status[VTERM] )
                                break;
                            settermstatus(FALSE);
                            break;
                        case 2: /* No Key Click */
                            setkeyclick(FALSE);
                            break;
                        case 3: /* Hold Screen Mode */
                            break;
                        case 4: /* Block Cursor */
                            tt_cursor = TTC_BLOCK ;
                            setcursormode() ;
                            break;
                        case 5: /* Cursor Off */
                            cursorena[VTERM] = FALSE ;
                            break;
                        case 6: /* Keypad Shifted */
                            tt_shift_keypad = TRUE ;
                            break;
                        case 7: /* Alternate keypad mode */
                            tt_keypad = TTK_APPL ;
                            break;
                        case 8: /* Auto Line Feed on receipt of CR */
                            tt_crd = TRUE ;
                            break;
                        case 9: /* Auto CR on receipt of LF */
                            tnlm = TRUE ;
                            break;

                        /* AnnArbor values */
                        case 25:        /* zMDM - Margin Bell Mode */
                            break;
                        case 26:        /* zKCM - Key Click Mode */
                            break;
                        case 27:        /* zKPCM - Key Pad Control Mode */
                            break;
                        case 28:        /* zKRM - Key Repeat Mode */
                            break;
                        case 29:        /* zRLM - Return Line Feed Mode */
                            break;
                        case 30:        /* zDBM - Destructive Backspace Mode */
                            break;
                        case 31:        /* zBKCM - Block Cursor Mode */
                            break;
                        case 32:        /* zBNCM - Blinking Cursor Mode */
                            break;
                        case 33:        /* zWFM - Wrap Forward Mode */
                            break;
                        case 34:        /* zWBM - Wrap Backward Mode */
                            break;
                        case 35:        /* zDDM - DEL character Display Mode */
                            break;
                        case 36:        /* zSPM - Scroll Page Mode */
                            break;
                        case 37:        /* zAXM - Auto Xoff/Xon Mode */
                            break;
                        case 38:        /* zAPM - Auto Pause Mode */
                            break;
                        case 39:        /* zSSM - Slow Scroll Mode */
                            break;
                        case 40:        /* zHDM - Half-Duplex Mode */
                            break;
                        case 41:        /* zTPDM - Transfer Pointer Display Mode */
                            break;
                        case 42:        /* zLTM - Line Transfer Mode */
                            break;
                        case 43:        /* zCSTM - Column Separator Transfer Mode */
                            break;
                        case 44:        /* zFSTM - Field Separator Transfer Mode */
                            break;
                        case 45:        /* zGRTM - Graphic Rendition Transfer Mode */
                            break;
                        case 46:        /* zAKDM - Auto Keyboard Disable Mode */
                            break;
                        case 47:        /* zFRM - Fast Repeat Mode */
                            break;
                        case 48:        /* zHAM - Hold in Area Mode */
                            break;
                        case 49:        /* zGAPM - Guarded Area Print Mode */
                            break;
                        case 51:        /* zACM - Alternate Cursor Mode */
                            break;
                        case 52:        /* zMKM - Meta Key Mode */
                            break;
                        case 53:        /* zCLIM - Caps Lock Invert Mode */
                            break;
                        case 54:        /* zINM - Ignore NUL Mode */
                            break;
                        case 55:        /* zCNM - CR New-Line Mode */
                            break;
                        case 56:        /* zICM - Invisible Cursor Mode */
                            break;
                        case 57:        /* zMMM - Meta Monitor Mode */
                            break;
                        case 59:        /* zIVM - Inverse Video Mode */
                            break;
                        case 61:        /* Z8RCM - 8-bit Remote Copy Mode */
                            break;
                        }
                    } else {      /* Not private */
                        if ( ISSCO(tt_type_mode) ) {
                            switch ( pn[j] ) {
                            case 2: /* Keyboard locked */
                                keylock = TRUE;
                                break;
                            case 3: /* 132 Columns */
                                RequestScreenMutex(SEM_INDEFINITE_WAIT);
                                killcursor(VTERM);
                                deccolm = TRUE;
                                Set132Cols(VTERM);
                                set_declrmm(FALSE);
                                naws();
                                setborder();
                                newcursor(VTERM);
                                clrscreen(VTERM,SP);
                                lgotoxy(VTERM,1,1);       /* and home the cursor */
                                ipadl25();
                                ReleaseScreenMutex();
                                break;
                            case 4: /* Smooth scroll */
                                SmoothScroll();
                                break;

                            case 6: /* Relative origin */
                                relcursor = TRUE;
                                home_cursor(vmode);
                                break;
                            case 7: /* Auto Wrap mode */
                                tt_wrap = TRUE;
                                break;
                            case 25:   /* Cursor On */
                            case 48:
                            case 1048:
                                cursorena[VTERM] = TRUE;
                                break;
                            case 30:    /* Scrollbars On */
                                break;
                            case 44:    /* Margin Bell On */
                                marginbell = TRUE;
                                break;
                            }
                        } else {
                            switch (pn[j]) {
                            case 2: /* Keyboard locked */
                                keylock = TRUE;
                                break;
                            case 3: /* CRM - Controls Mode On */
                                crm = TRUE ;
                                break;
                            case 4: /* ANSI insert mode */
                                if (ISVT102(tt_type_mode) ||
                                     ISANSI(tt_type_mode))
                                    insertmode = TRUE;
                                break;
                            case 6: /* Erasure Mode (ERM) Set */
                                erm = 1 ;
                                break;
                            case 12:        /* SRM - Send Receive ON */
                                if ( duplex_sav < 0 )
                                    duplex_sav = duplex ;
                                duplex = 0; /* Remote echo */
                                break;
                            case 13:        /* FEAM - Control execution off */
                                /* Display control codes */
                                break;
                            case 16:        /* TTM - Send through cursor position */
                                break;
                            case 20:
                                /* LNM - linefeed / newline mode */
                                tt_crd = tnlm = TRUE;
                                break;
                            case 30:        /* WYDSCM - Turn display off */
                                if ( ISWY370(tt_type_mode) ) {
                                    screenon = FALSE;
                                    if ( !savefiletext[0] )
                                        strcpy(savefiletext,filetext);
                                    strcpy(filetext,"SCREEN OFF") ;
                                    VscrnIsDirty(VTERM);
                                }
                                break;
                            case 31:        /* WYSTLINM - Display status line */
                                break;
                            case 32:        /* WYCTRSAVM - Screen Saver off */
                                break;
                            case 33:        /* WYSTCURM - Cursor steady */
                                break;
                            case 34:        /* WYULCURM - Underline cursor */
                                if ( ISWY370(tt_type_mode) ) {
                                    tt_cursor = TTC_ULINE ;
                                    setcursormode();
                                }
                                break;
                            case 35:        /* WYCLRM - Width change clear off */
                                break;
                            case 36:        /* WYDELKM - Set delete key to BS/DEL */
                                break;
                            case 37:        /* WYGATM - Send all characters */
                                break;
                            case 38:        /* WYTEXM - Send full page */
                                break;
                            case 40:        /* WYEXTDM - Extra data line */
                                break;
                            case 42:        /* WYASCII - Select Wyse 350 personality */
                                break;
                            case 50:    /* 97801-5XX - Compose key table on */
                                if ( IS97801(tt_type_mode) ) {
                                    break;
                                }
                                break;
                            case 51:    /* 97801-5XX - Dead key table on */
                                if ( IS97801(tt_type_mode) ) {
                                    break;
                                }
                                break;
                            case 53:    /* 97801-5XX - 132-character mode */
                                if ( IS97801(tt_type_mode) ) {
                                    RequestScreenMutex(SEM_INDEFINITE_WAIT);
                                    killcursor(VTERM);
                                    deccolm = TRUE;
                                    Set132Cols(VTERM);
                                    set_declrmm(FALSE);
                                    naws();
                                    setborder();
                                    newcursor(VTERM);
                                    clrscreen(VTERM,SP);
                                    lgotoxy(VTERM,1,1);       /* and home the cursor */
                                    ipadl25();
                                    ReleaseScreenMutex();
                                }
                                break;
                            default:
                                break;
                            }
                        }
                    }
                } /* for */
                break;
            case 'l':
                if ( ansiext && private ) {
                    /* Insert Line Up */
                    VscrnScroll(VTERM,
                                 UPWARD,
                                 0,
                                 wherey[VTERM] - 1,
                                 1,
                                 FALSE,
                                 SP,
                                 FALSE);
                    break;
                }
                else if (ansiext && ISSCO(tt_type_mode)) {
                    /* CHC - SCO - Clear and Home Cursor */
                    clrscreen(VTERM,SP);
					/* TODO: Apparently this should home the cursor obeying
							 the scrolling region. See:
						http://osr600doc.xinuos.com/en/man/html.HW/screen.HW.html */
                    lgotoxy(VTERM,1,1);
                    VscrnIsDirty(VTERM);
                }
                else {/* Reset Mode */
                    for (j = 1; j <= k; ++j) {/* Go thru all pn's */
                        if (private) {
                            switch ((pn[j])) {      /* Field specs */
                            case 1: /* DECCKM - Cursor key mode */
                                tt_arrow = TTK_NORM;
                                break;
                            case 2: /* DECANM : ANSI/VT52 */
                                if ( decsasd == SASD_TERMINAL ) {
                                    tt_type_vt52 = tt_type_mode ;
                                    tt_type_mode = TT_VT52;
                                    vt52graphics = FALSE;
                                    ipadl25();
                                }
                                break;
                            case 3: /* DECCOLM - 80 Columns */
                                RequestScreenMutex(SEM_INDEFINITE_WAIT);
                                killcursor(VTERM);
                                deccolm = FALSE;
                                Set80Cols(VTERM);
                                set_declrmm(FALSE);
                                naws();
                                setborder();
                                newcursor(VTERM);
                                clrscreen(VTERM,SP);
                                lgotoxy(VTERM,1,1);       /* and home the cursor */
                                ipadl25();
                                ReleaseScreenMutex();
                                break;
                           case 4: /* DECSCLM - Jump scrolling */
                               JumpScroll() ;
                               break;
                           case 5: /* DECSCNM - Normal screen */
                               if (!decscnm) /* Already normal? */
                                   break;
                               else {
                                   flipscreen(VTERM);
                                   VscrnIsDirty(VTERM);
                               }
                               break;
                           case 6: /* DECOM - Absolute origin */
                               relcursor = FALSE;
                               if ( decsasd == SASD_STATUS )
                                   lgotoxy( VSTATUS, 1, 1 );
                               else
                                   lgotoxy(VTERM,1, 1);
                               break;
                           case 7: /* DECAWM - Auto wrap */
                               tt_wrap = FALSE;
                               break;
                           case 8: /* DECARM - Auto repeat */
#ifdef NT
                               tt_autorepeat = FALSE;
#endif /* NT */
                               break;
                           case 9: /* DECINLM - Interlace. VT1xx only. */
                               /* XTERM - Don't Send Mouse X&Y on button press */
#ifdef OS2MOUSE
                               if (ISLINUX(tt_type_mode) || ISANSI(tt_type_mode) ||
                                 ISXTERM(tt_type_mode) || ISK95(tt_type_mode)) {
                                   /* The linux console terminal, as well as many
                                    * other terminal emulators, implement XTERM
                                    * mouse tracking */

                                   debug(F100, "X10 mouse tracking now OFF", "", 0);
                                   mouse_reporting_mode &= ~MOUSEREPORTING_X10;
                               }
#endif
                               break;
                           case 10:        /* DECEDM - Block mode off */
                               break;
						   case 12:			/* AT&T 610/xterm - Blinking cursor off */
							   tt_cursor_blink = 0;
							   break;
                               if (ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                   /* Toolbar off (rxvt) */
#ifdef KUI
#ifndef NOTOOLBAR
                                   KuiSetProperty(KUI_GUI_TOOLBAR_VIS, (intptr_t)0, 0L);
#endif
#endif
                            }
                            break;
                           case 18: /* DECPFF - Print Form Feed */
                               xprintff = FALSE;
                               break;
                           case 19:        /* DECPEX - Print extent */
                               printregion = TRUE; /* Region */
                               break;
                           case 25: /* DECTCEM - Cursor Off */
                               cursorena[VTERM] = FALSE;
                               break;
                           case 34:    /* DECRLM - Right to Left Mode */
                               debug(F111,"VT","DECRLM - Right to Left Mode",0);
                               break;
                           case 35: /* DECHEBM */
                               /* Enter English keyboard mode */
                               tt_kb_mode = KBM_EN ;
                               break;
                           case 36:    /* DECHEM - Hebrew Encoding Mode */
                               debug(F111,"VT","DECHEM - Hebrew Encoding Mode",0);
                               break;
                           case 38: /* DECTEK */
                               /* Exit Tektronix 4010/4014 mode */
                               resettekmode();
                               break;
                           case 40:
                               /* XTERM - Disallow 80 - 132 mode switch */
                               break;
                           case 41:
                               /* XTERM - No more(1) fix */
                               break;
                           case 42: { /* DECNRCM */
                               /* 8-bit multinational char set */

                               decnrcm = FALSE ;
                               for ( i = 0 ; i < 4 ; i++ ) {
                                   G[i].designation = G[i].def_designation ;
                                   G[i].size = G[i].def_size ;
                                   G[i].c1   = G[i].def_c1 ;
                                   G[i].national = CSisNRC(G[i].designation);
                                   if ( G[i].def_designation == FC_TRANSP ) {
                                       G[i].rtoi = NULL ;
                                       G[i].itol = NULL ;
                                       G[i].itor = NULL ;
                                       G[i].ltoi = NULL;
                                   }
                                   else {
                                       G[i].rtoi = xl_u[G[i].def_designation];
                                       if ( ck_isunicode() ) {
                                           G[i].itol = NULL ;
                                           G[i].ltoi = NULL;
                                       }
                                       else {
                                           G[i].itol = xl_tx[tcsl] ;
                                           G[i].ltoi = xl_u[tcsl] ;
                                       }
                                       G[i].itor = xl_tx[G[i].def_designation];
                                   }
                               }
                           }
                               break;
                           case 43: /* DECGEPM */
                               /* Graphics Normal Print mode */
                               break;
                           case 44: /* DECGPCM */
                               /* Graphics Print Monochrome mode */
                               /* XTERM - Turn off margin bell */
                               break;
                           case 45: /* DECGPCS */
                               /* Graphics Print Color syntax = HLS */
                               /* XTERM - No Reverse-wraparound mode */
                               break;
                           case 46: /* DECGPBM */
                               /* Graphics Print No-Background mode */
                               /* XTERM - Stop Logging */
                               break;
                           case 47: /* DECGRCM */
                               /* Graphics Unrotated Print mode */
                               /* XTERM - Use Normal Screen Buffer */
                               break;
                           case 53: /* DEC131TM */
                               /* VT131 Transmit */
                               break;
                           case 60: /* DECHCCM */
                               /* Horizontal cursor coupling */
                               break;
                           case 61: /* DECVCCM */
                               /* Vertical cursor coupling */
                               break;
                           case 64: /* DECPCCM */
                               /* Page cursor coupling */
                               if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
							       vscrn[VTERM].page_cursor_coupling = FALSE;
                               }
                               break;
                           case 66: /* DECNKM */
                               /* Numeric Keyboard - Numeric */
                               tt_keypad = TTK_NORM;
                               break;
                           case 67: /* DECBKM */
                               /* Backarrow key sends DEL */
                               if ( !savdecbkm )
                                   savdecbkm = keymap[KEY_SCAN | 8];
                               keymap[KEY_SCAN | 8] = DEL ;
                               break;
                           case 68: /* DECKBUM */
                               /* Keyboard Usage - Typewriter mode */
                               deckbum = 0 ;
                               break;
						   case 69: /* DECLRMM aka DECVSSM */
                               if (ISVT420(tt_type_mode) || ISK95(tt_type_mode) ||
                                   ISXTERM(tt_type_mode))
                               {
                                   set_declrmm(FALSE);
                               }
							   break;
                           case 73: /* DECXRLM */
                               /* Transmit rate limiting */
                               break;
                           case 80:        /* WY161 - 80-column mode */
                               if ( ISWY370(tt_type_mode) )
                               {
                                   tt_szchng[VTERM] = 1 ;
                                   tt_cols[VTERM] = 80 ;
                                   VscrnInit( VTERM ) ;  /* Height set here */
                                   naws();
                               }
                               break;
                           case 83:        /* WY52 - 24 line mode */
                               if ( ISWY370(tt_type_mode)) {
                                    set_term_height(24);
                               }
                               break;
                           case 84:        /* WYENAT */
                               if ( ISWY370(tt_type_mode) )
                                   /* Enable attribute assignment (SGR) */
                                   /* to extend to both eraseable and   */
                                   /* nonerasable characters            */
                                   ;
                               break;
                           case 85:        /* WYREPL */
                               if ( ISWY370(tt_type_mode) )
                                   /* Set replacement character to */
                                   /* color map background color   */
                                   ;
                               break;
                           case 95:
                                if (ISVT520(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                    decncsm = FALSE;
                                }
                                break;
                           case 114:      /* DECATCUM */
                               decatcum = FALSE;
                               break;
                           case 115:      /* DECATCBM */
                               decatcbm = FALSE;
                               break;
                           case 116: /* DECBBSM */
                               break;
                           case 117: /* DECECM */
                               /* On - erase with default/normal colour,
                                * Off - erase with current attribute colour */
                               if (ISVT525(tt_type_mode)) {
                                   erasemode = 0;
                               }
                               break;
                           case 1000:
                               /* XTERM - Don't Send Mouse X&Y on button press and release */
#ifdef OS2MOUSE
                               debug(F100, "X11 mouse tracking now OFF", "", 0);
                               mouse_reporting_mode &= ~MOUSEREPORTING_X11;
#endif
                               break;
                           case 1001:
                               /* XTERM - Don't use Hilite Mouse Tracking */
                               break;
                           case 1002:
                               /* XTERM - Cell Motion Mouse Tracking */
#ifdef OS2MOUSE
                               debug(F100, "Button-event mouse tracking now OFF", "", 0);
                               mouse_reporting_mode &= ~MOUSEREPORTING_BTNEVENT;
#endif
                               break;
                           case 1003:
                               /* XTERM - All Motion Mouse Tracking */
#ifdef OS2MOUSE
                               debug(F100, "Any-event mouse tracking now OFF", "", 0);
                               mouse_reporting_mode &= ~MOUSEREPORTING_ANYEVENT;
#endif
                               break;
                           case 1004:
                               /* XTERM - Send FocusIn/FocusOut events*/
#ifdef KUI
                                transmit_focus_change = FALSE;
#endif /* KUI */
                               break;
                           case 1005:
                               /* XTERM - UTF-8 Mouse Mode */
                               break;
                           case 1006:
                               /* XTERM - Disable SGR Mouse Mode */
#ifdef OS2MOUSE
                               debug(F100, "SGR mouse tracking now OFF", "", 0);
                               mouse_reporting_mode &= ~MOUSEREPORTING_SGR;
#endif
                               break;
                           case 1007:
                               /* XTERM - Alternate Scroll Mode */
                               break;
                           case 1010:
                               /* RXVT - Scroll to bottom on tty output */
                               break;
                           case 1011:
                               /* RXVT - Don't Scroll to bottom on key press */
                               tt_rkeys[VTERM] = TTRK_SND;
                               break;
                           case 1015:
                               /* URXVT - Disable URXVT Mosue Mode */
#ifdef OS2MOUSE
                               debug(F100, "URXVT mouse tracking now OFF", "", 0);
                               mouse_reporting_mode &= ~MOUSEREPORTING_URXVT;
#endif
                               break;
							case 1034:  /* xterm - turn off Interpret "meta" key */
								tt_kb_mode = KBM_EN;
								ipadl25();  /* Update the status line */
								break;
							case 1036:  /* xterm - Turn off Send esc when Meta modifies a key */
								tt_kb_mode = KBM_EN;
								ipadl25();  /* Update the status line */
								break;
                            case 1042:    /* xterm - disable urgency window hint on bell */
#ifdef KUI
                                tt_bell_flash = FALSE;
#endif /* KUI */
                                break;
                            case 1043:    /* xterm - do not raise window on bell */
#ifdef KUI
                                tt_bell_raise = FALSE;
#endif /* KUI */
                                break;
                            case 1046:    /* xterm - prevent switching to alternate buffer */
                                if (ISK95(tt_type) || ISXTERM(tt_type)) {
                                    set_alternate_buffer_enabled(vmode, FALSE);
                                    from_alternate_buffer(vmode);
                                }
                                break;
                            case 1047:    /* xterm - return from alternate screen */
                                if ((ISK95(tt_type) || ISXTERM(tt_type)) && vscrn[vmode].allow_alt_buf) {
                                    /* Clear the alternate screen */
                                    clrpage(vmode,
                                            ' ',
                                            ALTERNATE_BUFFER_PAGE(vmode));
                                    /* and switch back to the normal screen */
                                    from_alternate_buffer(vmode);
                                }
                                break;
                            case 1048:    /* xterm - restore cursor as in DECSC */
                                if (ISK95(tt_type) || ISXTERM(tt_type)) {
                                    restorecurpos(vmode, 1);
                                }
                                break;
                            case 1049:    /* xterm - to normal screen */
                                if ((ISK95(tt_type) || ISXTERM(tt_type)) && vscrn[vmode].allow_alt_buf) {
                                    from_alternate_buffer(vmode);
                                    restorecurpos(vmode, 1);
                                }
                                break;
                            case 2004:
                            	/* xterm - Disable Bracketed Paste Mode */
                            	bracketed_paste[vmode] = FALSE;
                            	break;
                            case 2026:
#ifdef KUI
                                if (ISK95(tt_type_mode)) {
                                    /* various - Synchronized Output */
                                    tt_sync_output = FALSE;
                                    tt_sync_output_timeout = 0;
                                    VscrnIsDirty(VTERM);
                                }
#endif
                                break;

                           default:
                               break;
                           }
                        } else if ( zdsext ) {
                           switch (pn[j]) {
                           /* Zenith/Heath */
                           case 1: /* Disable 25th line */
                               if ( tt_status[VTERM] )
                                   break;
                               settermstatus(TRUE);
                               break;
                           case 2: /* Key Click */
                               setkeyclick(TRUE);
                               break;
                           case 3: /* Exit Hold Screen Mode */
                               break;
                           case 4: /* Underline Cursor */
                               tt_cursor = TTC_ULINE ;
                               setcursormode() ;
                               break;
                           case 5: /* Cursor On */
                               cursorena[VTERM] = TRUE ;
                               break;
                           case 6: /* Keypad Unshifted */
                               tt_shift_keypad = FALSE ;
                               break;
                           case 7: /* Exit Alternate keypad mode */
                               tt_keypad = TTK_NORM ;
                               break;
                           case 8: /* No Auto Line Feed on receipt of CR */
                               tt_crd = FALSE ;
                               break;
                           case 9: /* No Auto CR on receipt of LF */
                               tnlm = FALSE ;
                               break;

                               /* AnnArbor values */
                           case 25:        /* zMDM - Margin Bell Mode */
                               break;
                           case 26:        /* zKCM - Key Click Mode */
                               break;
                           case 27:        /* zKPCM - Key Pad Control Mode */
                               break;
                           case 28:        /* zKRM - Key Repeat Mode */
                               break;
                           case 29:        /* zRLM - Return Line Feed Mode */
                               break;
                           case 30:        /* zDBM - Destructive Backspace Mode */
                               break;
                           case 31:        /* zBKCM - Block Cursor Mode */
                               break;
                           case 32:        /* zBNCM - Blinking Cursor Mode */
                               break;
                           case 33:        /* zWFM - Wrap Forward Mode */
                               break;
                           case 34:        /* zWBM - Wrap Backward Mode */
                               break;
                           case 35:        /* zDDM - DEL character Display Mode */
                               break;
                           case 36:        /* zSPM - Scroll Page Mode */
                               break;
                           case 37:        /* zAXM - Auto Xoff/Xon Mode */
                               break;
                           case 38:        /* zAPM - Auto Pause Mode */
                               break;
                           case 39:        /* zSSM - Slow Scroll Mode */
                               break;
                           case 40:        /* zHDM - Half-Duplex Mode */
                               break;
                           case 41:        /* zTPDM - Transfer Pointer Display Mode */
                               break;
                           case 42:        /* zLTM - Line Transfer Mode */
                               break;
                           case 43:        /* zCSTM - Column Separator Transfer Mode */
                               break;
                           case 44:        /* zFSTM - Field Separator Transfer Mode */
                               break;
                           case 45:        /* zGRTM - Graphic Rendition Transfer Mode */
                               break;
                           case 46:        /* zAKDM - Auto Keyboard Disable Mode */
                               break;
                           case 47:        /* zFRM - Fast Repeat Mode */
                               break;
                           case 48:        /* zHAM - Hold in Area Mode */
                               break;
                           case 49:        /* zGAPM - Guarded Area Print Mode */
                               break;
                           case 51:        /* zACM - Alternate Cursor Mode */
                               break;
                           case 52:        /* zMKM - Meta Key Mode */
                               break;
                           case 53:        /* zCLIM - Caps Lock Invert Mode */
                               break;
                           case 54:        /* zINM - Ignore NUL Mode */
                               break;
                           case 55:        /* zCNM - CR New-Line Mode */
                               break;
                           case 56:        /* zICM - Invisible Cursor Mode */
                               break;
                           case 57:        /* zMMM - Meta Monitor Mode */
                               break;
                           case 59:        /* zIVM - Inverse Video Mode */
                               break;
                           case 61:        /* Z8RCM - 8-bit Remote Copy Mode */
                               break;
                           }
                       } else { /* Not private */
                           if ( ISSCO(tt_type_mode) ) {
                               switch ( pn[j] ) {
                               case 2: /* Keyboard unlocked */
                                   keylock = FALSE;
                                   break;
                               case 3: /* 80 Columns */
                                   RequestScreenMutex(SEM_INDEFINITE_WAIT);
                                   killcursor(VTERM);
                                   deccolm = FALSE;
                                   Set80Cols(VTERM);
                                   set_declrmm(FALSE);
                                   naws();
                                   setborder();
                                   newcursor(VTERM);
                                   clrscreen(VTERM,SP);
                                   lgotoxy(VTERM,1,1);       /* and home the cursor */
                                   ipadl25();
                                   ReleaseScreenMutex();
                                   break;
                               case 4: /* Jump scroll */
                                   JumpScroll();
                                   break;
                               case 6: /* Absolute origin */
                                   relcursor = FALSE;
                                   if ( decsasd == SASD_STATUS )
                                       lgotoxy( VSTATUS, 1, 1 );
                                   else
                                       lgotoxy(VTERM,1, 1);
                                   break;
                               case 7: /* Auto wrap */
                                   tt_wrap = FALSE;
                                   break;
                               case 25:   /* Cursor Off */
                               case 48:
                               case 1048:
                                   cursorena[VTERM] = FALSE;
                                   break;
                               case 30:    /* Scrollbars Off */
                                   break;
                               case 44:    /* Margin Bell Off */
                                   marginbell = FALSE;
                                   break;
                               }
                           }
                           else switch (pn[j])
                           {
                           case 2: /* Keyboard unlocked */
                               keylock = FALSE;
                               break;
                           case 3: /* CRM - Controls Mode Off */
                               crm = FALSE ;
                               break;
                           case 4: /* ANSI insert mode */
                               if (ISVT102(tt_type_mode) ||
                                   ISANSI(tt_type_mode))
                                   insertmode = FALSE;
                               break;
                           case 6: /* Erasure Mode (ERM) Reset */
                               erm = 0 ;
                               break;
                           case 12: /* SRM - Send Receive OFF */
                               if ( duplex_sav < 0 )
                                   duplex_sav = duplex ;
                               duplex = 1; /* Local echo */
                               break;
                           case 13:        /* FEAM - Control execution on */
                               break;
                           case 16:        /* TTM - Send through EOL or EOS */
                               break;
                           case 20:
                               /* LNM - linefeed / newline mode */
                               tt_crd = tnlm = FALSE;
                               break;
                           case 30:        /* WYDSCM - Turn display on */
                               if ( ISWY370(tt_type_mode) ) {
                                   screenon = TRUE;
                                   if ( savefiletext[0] ) {
                                       strcpy(filetext,savefiletext);
                                       savefiletext[0] = NUL ;
                                       /* Update status line */
                                       VscrnIsDirty(VTERM);
                                   }
                               }
                               break;
                           case 31:        /* WYSTLINM - Turn off status line */
                               break;
                           case 32:        /* WYCTRSAVM - Screen Saver on */
                               break;
                           case 33:        /* WYSTCURM - Cursor blinking */
                               break;
                           case 34:        /* WYULCURM - Block cursor */
                               if ( ISWY370(tt_type_mode) ) {
                                   tt_cursor = TTC_BLOCK ;
                                   setcursormode() ;
                               }
                               break;
                           case 35:        /* WYCLRM - Width change clear on */
                               break;
                           case 36:        /* WYDELKM - Set delete key to DEL/CAN */
                               break;
                           case 37:        /* WHGATM - Send erasable characters */
                               break;
                           case 38:        /* WYTEXM - Send scrolling region */
                               break;
                           case 40:        /* WYEXTDM - Extra data line */
                               break;
                           case 50:    /* 97801-5XX - Compose key table off */
                               if ( IS97801(tt_type_mode) ) {
                                   /* Make compose key send Compose Key String */
                                   break;
                               }
                               break;
                           case 51:    /* 97801-5XX - Dead key table off */
                               if ( IS97801(tt_type_mode) ) {
                                   break;
                               }
                               break;
                           case 53:    /* 97801-5XX - 80-character mode */
                               if ( IS97801(tt_type_mode) ) {
                                   RequestScreenMutex(SEM_INDEFINITE_WAIT);
                                   killcursor(VTERM);
                                   deccolm = FALSE;
                                   Set80Cols(VTERM);
                                   set_declrmm(FALSE);
                                   naws();
                                   setborder();
                                   newcursor(VTERM);
                                   clrscreen(VTERM,SP);
                                   lgotoxy(VTERM,1,1);       /* and home the cursor */
                                   ipadl25();
                                   ReleaseScreenMutex();
                               }
                               break;
                           default:
                               break;
                           }
                       }
                    }
                } /* for */
                break;
            case 'i':       /* Media Copy */
                /*
                  This code crashes the 16-bit version with Stack Overflow.
                  Print-Whole-Screen & Print-Cursor-Line support added in edit 190, fdc.
                */
                if (pn[1] == 0)  /* Print whole screen */
                    prtpage(VTERM,
                               printregion ?
                               vscrn_c_page_margin_top(VTERM) :
                               1,
                               printregion ?
                               vscrn_c_page_margin_bot(VTERM) :
                               VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0),
                               vscrn[VTERM].cursor.p
                               );
                else if (pn[1] == 1 &&  /* Print cursor line */
                          /* Only if ESC [?1i */
                          private == TRUE)
                    prtpage(VTERM,wherey[VTERM],wherey[VTERM],vscrn[VTERM].cursor.p);
                /*
                Send Screen to Host computer
                #******************************************************************************#
                #                                                                              #
                #       Copyright (c) 1991-1993 Maximum Computer Technologies, Inc.            #
                #                           All Rights Reserved.                               #
                #       Version 1.2.0                                       09/15/93           #
                #                                                                              #
                #******************************************************************************#
                NAME        = ansi
                DESCRIPTION = Ansi standard console.
                ALIASES     = li|ansi|ansic|ansi80x25|scoansi|scoansic

                BEGIN_SCREEN_READ_CAPABILITIES

                Send_screen         = \E[2i
                End_send_screen     = \010
                Rcflowcntrloff      = NO
                Rsflowcntrloff      = NO
                Mustreposition      = NO
                Passthrough         = YES
                Mustpruneattribute  = NO

                END_SCREEN_READ_CAPABILITIES
                */
                else if ( pn[1] == 2 && !private ) {
                    int x,y,ch,
                    w=VscrnGetWidth(VTERM),
                    h=VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0),
                    xs=0,
                    ys=0,
                    xe=w-1,
                    ye=h-1;

                    /* Now send the data */
                    for ( y=ys;y<=ye; y++ ) {
                        for ( x=(y==ys)?xs:0 ; x <= (y==ye?xe:w-1) ; x++ ) {
                            ch = VscrnGetCell( VTERM, x, y, TRUE )->c;
                            if ( tt_senddata ) {
                                    unsigned char * bytes;
                                int nbytes;
                                if ( ck_isunicode() )
                                    nbytes = utorxlat(ch,&bytes);
                                else
                                    nbytes = utorxlat(ch,&bytes);
                                while ( nbytes-- > 0 )
                                    sendchar(*bytes++) ;
                            } else
                                sendchar(SP);
                            }   
                        if ( y < ye ) {
                            sendchar(CK_CR);
                            sendchar(LF);
                        }
                    }
                    sendchar(BS);
                }
                /* For pn = 4 or 5, we should differentiate here between transparent print  */
                /* (private == FALSE) and autoprint (private == TRUE).  As presently coded, */
                /* we always do transparent print.  Autoprint means that the current screen */
                /* line is printed as soon as the cursor leaves it, i.e. when the terminal  */
                /* receives a linefeed, form feed, or vertical tab, or when it wraps.       */
                /* Edit 191.  Now we distinguish between auto-print and transparent print.  */
                else if (pn[1] == 4) {
                    if ( private == TRUE ) {
                        setaprint(FALSE);
                    } else {
                        xprint = FALSE;
                    }
                    if ( is_noprint() )
                        turnoffprinter = TRUE;
                } else if (pn[1] == 5) {
                    if ( private == TRUE ) {
                        setaprint(TRUE);
                    } else {
                        xprint = TRUE ;
                    }
                    if ( !printon )
                        turnonprinter = TRUE;
                    }   

                    /*  6 and 7 are in the VT125 manual.*/
                    /* These are really ANSI Media Copy */
                    /* sequences which should control   */
                    /* the flow of data from the printer */
                    /* port to the host */
                else if (pn[1] == 6) {
                    if ( private == FALSE ) {
                        /* Turn off screen display */
                        screenon = FALSE;
                        if ( !savefiletext[0] )
                            strcpy(savefiletext,filetext);
                        strcpy(filetext,"SCREEN OFF") ;
                        VscrnIsDirty(VTERM);
                    }
                } else if (pn[1] == 7) {
                    if ( private == FALSE ) {
                        /* Turn on screen display */
                        screenon = TRUE;
                        if ( savefiletext[0] ) {
                            strcpy(filetext,savefiletext);
                            savefiletext[0] = NUL ;
                            /* Update status line */
                            VscrnIsDirty(VTERM);
                        }
                    }
                } else if (pn[1] == 8 && private) {
                    /* TODO: Disables communication from the printer port
                        to the host. Multi-session related? */
                } else if (pn[1] == 9 && private) {
                    /* TODO: Enables communication from the printer port
                        to the host. Multi-session related? */
                } else if (pn[1] == 10 && private
                        && (ISVT330(tt_type_mode) || ISVT420(tt_type_mode))) {
                    /* Print data on screen. DECPEX doesn't affect it. */
                    prtscreen(VTERM,
                              1,
                              VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0));
                } else if (pn[1] == 11 && private
                        && (ISVT330(tt_type_mode) || ISVT420(tt_type_mode))) {
                    int p;
                    /* Print all pages. */
                    for (p = 0; p < term_max_page(VTERM); p++) {
                        prtpage(VTERM,
                                printregion ?
                                    vscrn[VTERM].pages[p].margintop : 1,
                                printregion ?
                                    vscrn[VTERM].pages[p].marginbot :
                                    VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0),
                                p);
                    }
                }
                break;
            case 'k':       /* Keyclick */
            if ( pn[1] == 1 )
                    setkeyclick(FALSE);
                else if ( pn[1] == 0 )
                    setkeyclick(TRUE);
                break;
            case 'n':
                switch ( pn[1] ) {
                case 0:
                    /* SCO - Transmit Cursor Position */
                    if (ISSCO(tt_type_mode)) {
                        position * pos = VscrnGetCurPos(VTERM);
                        sprintf(tempstr,
                                 "%d %d\n",
                                 pos->y+1,
                                 pos->x+1
                                 );
                        sendchars(tempstr,strlen(tempstr));
                    }
                    break;
                case 5: /* Terminal Status Report */
                    /* Pages 103-104, VT220 manual */
                    sendescseq("[0n"); /* Terminal is OK */
                    break;
                case 6: {
                    /* Cursor position report (CPR/DECXCPR) */
                    /* Pages 103-104, VT220 manual */
                    position * pos = VscrnGetCurPos(VTERM);
                    if (private)
                        sprintf(tempstr,
                                "[?%d;%d;%dR",
                                pos->y+1,
                                pos->x+1,
                                pos->p+1
                                );
                    else
                        sprintf(tempstr,"[%d;%dR",
                                pos->y+1,
                                pos->x+1
                                );
                    sendescseq(tempstr);
                    break;
                }
#ifdef COMMENT
				/* My VT520 doesn't respond to either of these, and I don't see
					them in any DEC documentation. I wonder what terminal they
					were for?  -DG */
                case 7:
                    if ( private ) {
                        /* Request Time ("HH:MM:SS"<CR>) */
                        char response[32];
                        sprintf(response,"\"%2d:%2d:%2d\"\r",
                                0,0,0);
                        sendchars(response,strlen(response));
                    }
                    break;
                case 8: /* Request Date ("mmdddyy"<CR>) */
                    if ( private ) {
                        char response[32];
                        sprintf(response,"\"%2d%3s%2d\"\r",
                                1,"jan",80);
                        sendchars(response,strlen(response));
                    }
                    break;
#endif /* COMMENT */
                case 15: {
                    /* DECDSR Printer status */
                    sendescseq("[?10n"); /* Printer is ready */
                    break;
                }
                case 25: {
                    /*
                      DECDSR UDK status;
                      20=unlocked, 21=locked
                      */
                    if ( udklock )
                        sendescseq("[?21n");
                    else
                        sendescseq("[?20n");
                    break;
                }
                case 26: {
                    /*
                      DECDSR Keyboard language, UK or US
                      */
                    sendescseq((G[0].designation == TX_BRITISH) ?
                               "[?27;2n" :
                               "[?27;1n" );
                    break;
                }
				case 62: {
					/*
					  DECDSR Macro Space Report (VT420+)
						Responds with a DECMSR containing available macro space.
						Limit is different for K95 terminal type.
					 */
					if (ISVT420(tt_type_mode)) {
						int limit = MACRO_SIZE_LIMIT(tt_type_mode);
						unsigned int result = (unsigned int)floor((limit - vt_macro_size) / 16);
						char buf[20];
						_snprintf(buf, 20, "[%d*{", result);
						sendescseq(buf);
					}
					break;
				}
				case 63: {
					/*
					  DECDSR Memory Checksum (DECCKSR)
						Responds with a simple checksum of any stored text
						macros.
					 */
					if (ISVT420(tt_type_mode)) {
						int pid = k > 1 ? pn[2] : 0;
						unsigned short result = 0;
						char buf[20];
						int i;

						for (i = 0; i < 64; i++) {
							if (vt_macro_definitions[i]) {
								int j;
								int len = strlen(vt_macro_definitions[i]);
								for (j = 0; j < len; j++) {
									result -= vt_macro_definitions[i][j];
								}
							}
						}

						if ( send_c1) {
							_snprintf(buf, 20, "%c%d!~%04X%c",
								_DCS, pid, result, _ST8);
						} else {
							_snprintf(buf, 20, "\033P%d!~%04X\033\\",
								pid, result, send_c1 ? 0x9C : 0x1B);
						}
						sendchars(buf, strlen(buf));
					}
					break;
				}
            case 85: {
                    if (private && ISVT420(tt_type_mode)) {
                        /* Multiple-Session Configuration Status Report */

                        /* Not configured for multiple sessions */
                        sendescseq("[?83n");
                    }
                }
                }
                break;
            case 'o': 
                if ( ISSCO(tt_type_mode) ) {
                    /* SCO - Transmit Margin Position */

                    switch ( pn[1] ) {
                    case '0': /* all margins */
                        sprintf(tempstr,
                                 "%d %d %d %d\n",
                                 vscrn_c_page_margin_top(VTERM),
                                 vscrn_c_page_margin_bot(VTERM),
                                 vscrn_c_page_margin_left(VTERM),
                                 vscrn_c_page_margin_right(VTERM)
                                 );
                        sendchars(tempstr,strlen(tempstr));
                        break;
                    case '1':
                        sprintf(tempstr,
                                 "%d\n",
                                 vscrn_c_page_margin_top(VTERM)
                                 );
                        sendchars(tempstr,strlen(tempstr));
                        break;
                    case '2':
                        sprintf(tempstr,
                                 "%d\n",
                                 vscrn_c_page_margin_bot(VTERM)
                                 );
                        sendchars(tempstr,strlen(tempstr));
                        break;
                    case '3':
                        sprintf(tempstr,
                                 "%d\n",
                                 vscrn_c_page_margin_left(VTERM)
                                 );
                        sendchars(tempstr,strlen(tempstr));
                        break;
                    case '4':
                        sprintf(tempstr,
                                 "%d\n",
                                 vscrn_c_page_margin_right(VTERM)
                                 );
                        sendchars(tempstr,strlen(tempstr));
                        break;
                    }
                } else if (ISAAA(tt_type_mode)) {
                    /* DAQ - Define Area Qualification */

                }
                break;
            case 'p':   /* Proprietary */
                if ( ISH19(tt_type) ) {
                    /* Transmit Page to host */
                    break;
                } else if ( ISAAA(tt_type_mode) ) {
                    /* zSDP - Set Display Parameters Pn1;Pn2;...;Pn6 
                     *
                     * Pn1 - Active Memory Lines 
                     * Pn2 - Upper Host Area Lines
                     * Pn3 - Lower Host Area Lines
                     * Pn4 - Screen Lines 
                     * Pn5 - Screen Columns
                     * Pn6 - Active Memory Columns
                     */
                    if ( pn[1] <= pn[2] + pn[3] ||
                         pn[4] <= pn[2] + pn[3] + 1 ||
                         (k > 4) && (pn[6] <= pn[5]))
                        break;

		    /* Kermit is not going to do the right thing 
		     * Since we do not support memory pages different
		     * than the actual screen size, we ignore everything
		     * but the memory lines
		     */
            /* Actually, we *could* do the right thing - memory pages wider
             * than the screen have been supported for years, and VT420
             * emulation will eventually require support for taller memory
             * pages too. Problem is getting access to an AAA to confirm what
             * exactly the right thing is...
             *     - DavidG */
#ifdef KUI
                    tt_linespacing[VTERM] = (CKFLOAT)pn[1] / (CKFLOAT)pn[4];
                    gui_resize_mode(0);
#endif /* KUI */
                    tt_szchng[VTERM] = 1 ;
#ifdef COMMENT
                    tt_rows[VTERM] = pn[4];
#else
                    tt_rows[VTERM] = pn[1];
                    vscrn_setc_page_margin_bot(VTERM, pn[4]);
#endif /* COMMENT */
                    if (k > 4)
                        tt_cols[VTERM] = pn[5];
                    VscrnInit( VTERM ) ;  /* Height set here */
                    VscrnSetDisplayHeight(VTERM, pn[1] != pn[4] ? pn[4] : 0);
                    naws();
                    break;
                } else if ( ISSUN(tt_type_mode) ) {
                    /* 
                    ESC[p       Black On White (SUNBOW)
                    Takes no parameters.  Sets the screen  mode  to  black-
                    on-white.   If  the  screen  mode  is already black-on-
                    white, has no effect.  In this mode spaces  display  as
                    solid  white,  other characters as black-on-white.  The
                    cursor is a solid black block.  Characters displayed in
                    negative  image  rendition  (see `Select Graphic Rendi-
                    tion' above) is white-on-black in this mode.   This  is
                    the initial setting of the screen mode on reset.
                    */
                }
                else if ( IS97801(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 0: /* Blinking on, lines 1-25 or 1-24 */
                        break;
                    case 1: /* Blinking off, lines 1-25 or 1-24 */
                        break;
                    case 2: /* Blinking on, line 25 */
                        break;
                    case 3: /* Blinking off, line 25 */
                        break;
                    case 5: /* Request abbreviated cursor position */
                        {
                            /* Respond with <FS> <line + 0x20> <col + 0x20>, 0 based */
                            char buf[4];
                            buf[0] = XFS;
                            buf[1] = wherey[1] + SP - 1;
                            buf[2] = wherex[1] + SP - 1;
                            buf[3] = NUL;
                            sendchars(buf,3);
                        }
                        break;
                    case 6: /* Cursor not visible */
                        cursorena[VTERM] = FALSE;
                        break;
                    case 7: /* Activate cursor */
                        cursorena[VTERM] = TRUE;
                        break;
                    case 8: /* Display off */
                        /* This is supposed to fill the viewable      */
                        /* screen with blanks but continue processing */
                        /* additional chars into the display buffer   */
                        screenon = FALSE;
                        if ( !savefiletext[0] )
                            strcpy(savefiletext,filetext);
                        strcpy(filetext,"SCREEN OFF") ;
                        VscrnIsDirty(VTERM);
                        break;
                    case 9: /* Display on */
                        /* Re-enable viewing the display buffer with  */
                        /* real data.                                 */
                        screenon = TRUE;
                        if ( savefiletext[0] ) {
                            strcpy(filetext,savefiletext);
                            savefiletext[0] = NUL ;
                            /* Update status line */
                            VscrnIsDirty(VTERM);
                        }
                        break;
                    case 10: /* Single inverting block cursor */
                        tt_cursor = TTC_HALF;
                        setcursormode();
                        cursorena[VTERM] = TRUE;
                        break;
                    case 11: /* Activate block cursor */
                        tt_cursor = TTC_BLOCK;
                        setcursormode();
                        cursorena[VTERM] = TRUE;
                        break;
                    case 12: /* Activate underscore cursor */
                        tt_cursor = TTC_ULINE;
                        setcursormode();
                        cursorena[VTERM] = TRUE;
                        break;
                    case 13: /* Activate cursor blinking */
                        break;
                    case 14: /* Deactivate cursor blinking */
                        break;
                    }
                }
                break;
            case 'q':   /* Proprietary */
                if ( ISH19(tt_type) ) {
                    /* Transmit 25th line to host */
                    break;
                } else if ( ISSUN(tt_type_mode) ) {
                    /*
                    ESC[q       White On Black (SUNWOB)
                    Takes no parameters.  Sets the screen  mode  to  white-
                    on-black.   If  the  screen  mode  is already white-on-
                    black, has no effect.  In this mode spaces  display  as
                    solid  black,  other characters as white-on-black.  The
                    cursor is a solid white block.  Characters displayed in
                    negative  image  rendition  (see `Select Graphic Rendi-
                    tion' above) is black-on-white in this mode.  The  ini-
                    tial  setting of the screen mode on reset is the alter-
                    native mode, black on white.
                    */
                }
                else if ( IS97801(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 0: /* CH.CODE LED off */
                        /* does not affect actual mode */
                        break;
                    case 6: /* CH.CODE LED on */
                        /* does not affect actual mode */
                        break;
                    }
                    break;
                }
				if (zdsext && (ISXTERM(tt_type_mode) || ISK95(tt_type_mode))) {
					if (k < 1) pn[1] = 0;
					switch (pn[1]) {
					case 0: /* XTVERSION */
						{
							/* TODO: If we were emulating XTerm, then ideally
							 *  	 we'd respond with the version of XTerm we
							 * 		 are emulating. */
							char resp[256] ;
							extern char *ck_s_name;
							extern char *ck_s_xver;
							if (send_c1) {
                        		sprintf(resp, "P>|%s %s%c",
                                 	ck_s_name,
                                 	ck_s_xver,
								 	_ST8);
							} else {
								sprintf(resp, "P>|%s %s%c\\",
                                 	ck_s_name,
                                 	ck_s_xver,
								 	ESC);
							}
                        	sendescseq(resp);
						}
						break;
					default:
						break;
					}
                } else {
                    /* Load LEDs */
                    for ( i=1 ; i<=k ; i++ ) {
                        switch ( pn[i] ) {
                        case 0:
                            decled[0] = decled[1] =
                                decled[2] = decled[3] = FALSE ;
                            break;
                        case 1:
                        case 2:
                        case 3:
                        case 4:
                            decled[ pn[i]-1 ] = TRUE ;
                            break;
                        case 21:
                        case 22:
                        case 23:
                        case 24:
                            decled[ pn[i]-21 ] = FALSE ;
                            break;
                        }
                    }
                    ipadl25() ;
                }
                break;
            case 'x':   /* Proprietary */
                if ( ISWY370(tt_type_mode) ) {
                    /* Set Color and Attribute */
                    /* pn[1] - 64 color palette - fg */
                    /* pn[2] - 64 color palette - bg */
                    /* pn[3] - attribute             */
                    switch ((pn[3])) {   /* This one... */
                    case 0: /* Set all attributes to normal */
                        if (colorreset)
                            resetcolors(0);

                        attrib.blinking = FALSE;
                        attrib.italic = FALSE;              /* No italic */
                        attrib.bold = FALSE;
                        attrib.invisible = FALSE;
                        attrib.underlined = FALSE;
                        attrib.reversed = FALSE;
                        attrib.graphic = FALSE ;
                        attrib.dim = FALSE ;
						attrib.crossedout = FALSE ;
                        attrib.erased = FALSE;
                        attrib.wyseattr = FALSE ;
                        attrib.hyperlink = FALSE;
                        attrib.linkid = 0;

                        sco8bit = FALSE ;

                        if ( ISANSI(tt_type_mode) )
                            crm = FALSE ;
                        break;
                    case 1: /* Turn on BOLD */
                        /* No colors involved. */
                        if (attrib.bold) /* Already bold? */
                            break;
                        attrib.bold = TRUE; /* Remember */
                        break;
                    case 2: /* Turn on DIM (QANSI) */
                        /* No colors involved. */
                        if (attrib.dim) /* Already dim? */
                            break;
                        attrib.dim = TRUE; /* Remember */
                        break;
                    case 3: /* Turn on ITALIC (ANSI X3.64) */
                        if ( tt_type_mode == TT_AT386 &&
                             !trueitalic ) {
                            if ( colorreset )
                                resetcolors(0);
                            attribute = italicattribute;
                        }
                        else {
                            if (attrib.italic)
                                break;
                            attrib.italic = TRUE;
                        }
                        break;
                    case 4: /* Turn on UNDERLINE */
                        if ( tt_type_mode == TT_AT386 &&
                             !trueunderline ) {
                            if ( colorreset )
                                resetcolors(0);
                            attribute = underlineattribute;
                        }
                        else {
                            if (attrib.underlined)
                                break;
                            attrib.underlined = TRUE;
                        }
                        break;
                    case 5: /* Turn on Slow BLINK */
                        /* Simulated by background intensity) */
                        if ( attrib.blinking )
                            break;
                        attrib.blinking = TRUE;
                        break;
                    case 6: /* Turn on Fast BLINK */
                        if ( attrib.blinking )
                            break;
                        attrib.blinking = TRUE ;
                        break;
                    case 7: /* Turn on REVERSE VIDEO */
                        if ( tt_type_mode == TT_AT386 ) {
                            if ( colorreset )
                                resetcolors(0);
                            attribute = swapcolors(attribute);
                        }
                        else {
                            if (attrib.reversed)
                                break;
                            attrib.reversed = TRUE;
                        }
                        break;

                        /* 8 - 12 are ANSI X3.64 */
                    case 8: /* Turn on INVISIBLE */
                    case 9: /* Turn on INVISIBLE (QANSI) */
                        attrib.invisible = TRUE; /* see wrtch */
                        break;
                    }
                    if ( !sgrcolors )
                        break;
                    /* pn[1] - 64 color palette - fg */
                    /* pn[2] - 64 color palette - bg */
#ifdef CK_COLORS_16
                    /* TODO: This behaviour is totally wrong. Ideally we'd
                     *    use color quantization to try and find the nearest
                     *    match in the 16-color palette, but doing that requires
                     *    us to know the RGB values for the WY370 palette
                     */
                    l = sgrcols[(decscnm?pn[2]:pn[1])%8];
                    attribute = cell_video_attr_set_3bit_bg_color(attribute, l);

                    l = sgrcols[(decscnm?pn[1]:pn[2])%8];
                    attribute = cell_video_attr_set_3bit_fg_color(attribute, l);
#else
                    {
                        int bg_index, fg_index, max_colors;


                        max_colors = current_palette_max_index();

                        bg_index = (decscnm?pn[2]:pn[1]);
                        fg_index = (decscnm?pn[1]:pn[2]);

                        if (bg_index < max_colors) {
                            attribute = cell_video_attr_set_bg_color(attribute, bg_index);
                        }
                        if (fg_index < max_colors) {
                            attribute = cell_video_attr_set_fg_color(attribute, fg_index);
                        }
                    }
#endif
                    break;
                }

                /* DECREQTPARM Request Terminal Parameters */
                if (pn[1] > 1)
                    break;
                tempstr[0] = '[';
                tempstr[1] = (pn[1] == 0) ? '2' : '3';
                tempstr[2] = ';';
                tempstr[5] = '2'; /* Nbits = 7 */
                switch (parity) {
                case 0:
                    tempstr[3] = '1'; /* Parity = None */
                    /* Nbits depends on TERMINAL BYTESIZE */
                    if (cmask == 0xFF)
                        tempstr[5] = '1'; /* Nbits = 8 */
                    break;
                case 'e':
                    tempstr[3] = '5'; /* Parity = Even */
                    break;
                case 'o':
                    tempstr[3] = '4'; /* Parity = Odd */
                    break;
                case 'm':
                    tempstr[3] = '3'; /* Parity = Mark */
                    break;
                default:
                    tempstr[3] = '2'; /* Parity = Space */
                    break;
                }
                tempstr[4] = ';';
                switch (speed) {
                case 50:
                    i = 0;
                    break;
                case 75:
                    i = 8;
                    break;
                case 110:
                    i = 16;
                    break;
                case 133:
                    i = 14;
                    break;
                case 150:
                    i = 32;
                    break;
                case 200:
                    i = 40;
                    break;
                case 300:
                    i = 48;
                    break;
                case 600:
                    i = 56;
                    break;
                case 1200:
                    i = 64;
                    break;
                case 1800:
                    i = 72;
                    break;
                case 2000:
                    i = 80;
                    break;
                case 2400:
                    i = 88;
                    break;
                case 3600:
                    i = 96;
                    break;
                case 4800:
                    i = 104;
                    break;
                case 9600:
                    i = 112;
                    break;
                case 19200: /* Really the 19200 value */
                    i=120;
                    break;
                case 38400: /* but it's the highest one */
                    i=128;
                    break;
                case 57600:
                case 115200:
                case 230400:
                case -1: /*  Lie about networks too */
                    i = 128;
                    break;
                default: /* UNKNOWN speed - not true */
                    i = 128;
                    break;
                }
                sprintf(&tempstr[6], ";%d;%d;1;0x", i, i);
                sendescseq(tempstr);
                break;
            case '}':       /* (Why this?) */
            case 'm':
                if ( ansiext && private ) {
                    /* Delete Line Up */
                    VscrnScroll(VTERM,
                                DOWNWARD,
                                0,
                                wherey[VTERM] - 1,
                                1,
                                FALSE,
                                SP,
                                FALSE);
                    break;
                } else if ( ansiext && ISSCO(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 0: /* top margin */
						vscrn_setc_page_margin_top(VTERM, pn[2]);
                        break;
                    case 1: /* bottom margin */
                        vscrn_setc_page_margin_bot(VTERM, pn[2]);
                        break;
                    case 2: /* left margin */
                        vscrn_setc_page_margin_left(VTERM, pn[2]);
                        break;
                    case 3: /* right margin */
                        vscrn_setc_page_margin_right(VTERM, pn[2]);
                        break;
                    }
                } else { /* Select Graphic Rendition (SGR) */
                    for (j = 1; j <= k; ++j) { /* Go thru all Pn's */
                        switch ((pn[j])) {   /* This one... */
                        case 0: /* Set all attributes to normal */
                            if (colorreset)
                                resetcolors(0);

                            attrib.blinking = FALSE;
                            attrib.italic = FALSE;              /* No italic */
                            attrib.bold = FALSE;
                            attrib.invisible = FALSE;
                            attrib.underlined = FALSE;
                            attrib.reversed = FALSE;
                            attrib.graphic = FALSE ;
                            attrib.dim = FALSE ;
                            attrib.wyseattr = FALSE ;
                            attrib.hyperlink = FALSE;
							attrib.crossedout = FALSE;
                            attrib.erased = FALSE;
                            attrib.linkid = 0;

                            sco8bit = FALSE ;

                            if ( ISANSI(tt_type_mode) )
                                crm = FALSE ;
                            break;
                        case 1:     /* Turn on BOLD */
                            /* No colors involved. */
                            if (attrib.bold) /* Already bold? */
                                break;
                            attrib.bold = TRUE; /* Remember */
                            break;
                        case 2:
                            if ( ISSCO(tt_type_mode) ) {
                                /* Select fg/bg iso colors while preserving the
                                 * intensity bit. */
                                if ( !sgrcolors )
                                    break;
                                if (decscnm) {
                                    attribute = cell_video_attr_set_vio_3bit_colors(attribute, (((pn[j+1] & 0x07) << 4)) | (pn[j+2] & 0x07));
                                    defaultattribute = attribute;
                                    graphicattribute = attribute;

                                    reverseattribute = cell_video_attr_set_vio_3bit_colors(attribute, (((pn[j+2] & 0x07) << 4)) | (pn[j+1] & 0x07));
                                    /* reverseattribute = attribute; */
                                } else {
                                    attribute = cell_video_attr_set_vio_3bit_colors(attribute, (((pn[j+2] & 0x07) << 4)) | (pn[j+1] & 0x07));
                                    defaultattribute = attribute;
                                    graphicattribute = attribute;

                                    reverseattribute = cell_video_attr_set_vio_3bit_colors(attribute, (((pn[j+1] & 0x07) << 4)) | (pn[j+2] & 0x07));
                                    /* reverseattribute = attribute; */
                                }
                                j += 2;
                            } else {
                                /* Turn on DIM (QANSI) */
                                /* No colors involved. */
                                if (attrib.dim) /* Already dim? */
                                    break;
                                attrib.dim = TRUE; /* Remember */
                            }
                            break;
                        case 3:
                            if ( ISSCO(tt_type_mode) ) {
                                /* Turn on Italic */
                                /* pn[j+1] determines blink or bold background*/
                                if (attrib.italic)
                                    break;
                                attrib.italic = TRUE;
                                j++;
                                break;
                            } else {
                                /* Turn on ITALIC (ANSI X3.64) */
                                if (attrib.italic)
                                    break;
                                attrib.italic = TRUE;
                            }
                            break;
                        case 4:     /* Turn on UNDERLINE */
                            if ( tt_type_mode == TT_AT386 &&
                                !trueunderline ) {
                                if ( colorreset )
                                    resetcolors(0);
                                attribute = underlineattribute;
                            }
                            else {
                                if (attrib.underlined)
                                    break;
                                attrib.underlined = TRUE;
                            }
                            break;
                        case 5:
                            if ( ISSCO(tt_type_mode) ) {
                                /* Turn on Blink Mode */
                                if ( attrib.blinking )
                                    break;
                                attrib.blinking = TRUE;
                            } else {
                                /* Turn on Slow BLINK */
                                /* Simulated by background intensity) */
                                if ( attrib.blinking )
                                    break;
                                attrib.blinking = TRUE;
                            }
                            break;
                        case 6:
                            if ( ISSCO(tt_type_mode) ) {
                                /* Turn off Blink Mode */
                                if ( !attrib.blinking )
                                    break;
                                attrib.blinking = FALSE;
                            } else {
                                /* Turn on Fast BLINK */
                                if ( attrib.blinking )
                                    break;
                                attrib.blinking = TRUE ;
                            }
                            break;
                        case 7: /* Turn on REVERSE VIDEO */
                            if ( tt_type_mode == TT_AT386 ) {
                                if ( colorreset )
                                    resetcolors(0);
                                attribute = swapcolors(attribute);
                            }
                            else {
                                if (attrib.reversed)
                                    break;
                                attrib.reversed = TRUE;
                            }
                            break;

                            /* 8 - 12 are ANSI X3.64 */
                        case 9: /* Turn on INVISIBLE (QANSI) */
                                /* Turn on Crossed-Out characters (ANSI) */
							if (!ISQANSI(tt_type_mode)) {
								attrib.crossedout = TRUE;
								break;
							}
							/* Fall through - Turn on INVISIBLE (QANSI) */
						case 8: /* Turn on INVISIBLE */
                            attrib.invisible = TRUE; /* see wrtch */
                            break;

                        case 10:  /* Select Primary font */
                            if (ISANSI(tt_type_mode) ||
                                ISBEOS(tt_type_mode))
                            {
                                sco8bit = FALSE;
                                crm = FALSE ;
                                attrib.graphic = FALSE ;
                                GR = &G[1];
                                if ( tt_type_mode == TT_AT386 && colorreset ||
                                     ISSCO(tt_type_mode) && scocompat )
                                    resetcolors(0);
                            } else if (ISLINUX(tt_type_mode) ||
                                       ISQANSI(tt_type_mode)) {
                                sco8bit = FALSE;
                                crm = FALSE;
                                if ( Qsaved ) {
                                    int i;
                                    Qsaved = FALSE;
                                    for ( i=0;i<4;i++ )
                                        G[i] = QsavedG[i];
                                }
                            }
                            break;
							/* IBM HFT - we *should* fall through here */

                        case 11:  /* Display GL Control Characters */
                            /* as Graphic Characters */
                            if ( ISANSI(tt_type_mode) )
                            {
                                sco8bit = FALSE ;
                                crm = TRUE;
                                GR = &G[2];
                                if ( tt_type_mode == TT_AT386 && colorreset ||
                                     ISSCO(tt_type_mode) && scocompat )
                                    resetcolors(0);
                                attribute = graphicattribute ;
                            }
                            else if (ISLINUX(tt_type_mode)) {
                                int i;
                                sco8bit = TRUE ;
                                crm = TRUE;
                                if ( !Qsaved ) {
                                    Qsaved = TRUE;
                                    for ( i=0;i<4;i++ )
                                        QsavedG[i] = G[i];
                                }
                                for ( i=1;i<4;i++ )
                                    charset(cs94,'U',&G[i]);
                            }
                            else if (ISQANSI(tt_type_mode)) {
                                int i;
                                sco8bit = TRUE ;
                                crm = TRUE;
                                if ( !Qsaved ) {
                                    Qsaved = TRUE;
                                    for ( i=0;i<4;i++ )
                                        QsavedG[i] = G[i];
                                }
                                for ( i=1;i<3;i++ )
                                    charset(cs94,'*',&G[i]);
                            }
                            break;
							/* IBM HFT - we *should* fall through here */

                        case 12:
                            if (ISLINUX(tt_type_mode)) {
                                /*
                                select null mapping (CP437),
                                set display control flag,
                                set toggle meta flag. (The toggle meta flag
                                causes the high bit of a byte to be toggled
                                before the mapping table translation is done.)
                                */
                                int i;
                                sco8bit = TRUE ;
                                crm = TRUE ;
                                attrib.graphic = FALSE ;
                                if ( !Qsaved ) {
                                    Qsaved = TRUE;
                                    for ( i=0;i<4;i++ )
                                        QsavedG[i] = G[i];
                                }
                                for ( i=1;i<4;i++ )
                                    charset(cs94,'U',&G[i]);
                                break;
                            }
							/* fall through - IBM HFT */
                        case 13: /* IBM HFT */
                        case 14: /* IBM HFT */
                        case 15: /* IBM HFT */
                        case 16: /* IBM HFT */
                        case 17: /* IBM HFT */
                            /* Shift High Bit on before displaying */
                            /* Characters */
                            if ( ISANSI(tt_type_mode) ||
                                ISBEOS(tt_type_mode))
                            {
                                sco8bit = TRUE ;
                                crm = FALSE ;
                                attrib.graphic = FALSE ;
                                GR = &G[3];

                                if ( tt_type_mode == TT_AT386 &&
                                    colorreset )
                                    resetcolors(0);
                            } else if (ISQANSI(tt_type_mode)) {
                                int i;
                                sco8bit = TRUE ;
                                crm = FALSE;
                                if ( !Qsaved ) {
                                    Qsaved = TRUE;
                                    for ( i=0;i<4;i++ )
                                        QsavedG[i] = G[i];
                                }
                                for ( i=1;i<3;i++ )
                                    charset(cs94,'U',&G[i]);
                            }
							break;

                        case 21: { /* Set Normal Intensity */
							if (ISLINUX(tt_type_mode)) {
								/* Since linux 4.17. Prior to this, it was normal
								 * intensity */
								attrib.underlined = TRUE;
							} else {
	                            if (attrib.bold)
	                                attrib.bold = FALSE;
                            	if (attrib.dim)
                            	    attrib.dim = FALSE;
							}
                            break;
							}
                        case 22: /* Turn BOLD Off */
                            if (attrib.bold)
                                attrib.bold = FALSE;
                            if (attrib.dim)
                                attrib.dim = FALSE;
                            break;
                        case 23: /* Turn ITALIC off */
                            if (!attrib.italic)
                                break;
                            attrib.italic = FALSE;
                            break;

                        case 24: /* Turn UNDERLINE Off */
                            if (!attrib.underlined)
                                break;
                            attrib.underlined = FALSE;
                            /* Go back to normal coloring */
                            break;
                        case 25: /* Turn BLINK Off */
                            if (!attrib.blinking)
                                break;
                            attrib.blinking = FALSE;
                            break;
                        case 26: /* Turn BLINK On */
                            if ( ISSCO(tt_type_mode)) {
                                if (attrib.blinking)
                                    break;
                                attrib.blinking = TRUE;
                            } else {
                                if (!attrib.blinking)
                                    break;
                                attrib.blinking = FALSE;
                            }
                            break;
                        case 27: /* Turn REVERSE VIDEO Off */
                            if (!attrib.reversed)
                                break;
                            attrib.reversed = FALSE;
                            break;

                        case 29:
							if (!ISQANSI(tt_type_mode)) {
								attrib.crossedout = FALSE;
								break;
							}
							/* Fall through - QANSI INVISIBLE off */
						case 28:/* Turn INVISIBLE Off */
                            if (!attrib.invisible)
                                break;
                            attrib.invisible = FALSE;
                            break;


                        case 30: /* Colors */
                        case 31:
                        case 32:
                        case 33:
                        case 34:
                        case 35:
                        case 36:
                        case 37:
                            /* Select foreground color */
                            if ( !sgrcolors )
                                break;

                            /* Historically, Kermit 95 preserved the intensity
                             * bit here. I don't know why, but I *assume* it was
                             * intentional. Perhaps aixterm or one of the other
                             * terminals it emulates originally did this too.
                             * Whatever the reason, the result is that something
                             * like '\033[96m\033[36m' would give in intense
                             * cyan instead of regular cyan. I can't find any
                             * other common terminals that behave this way which
                             * results in this behaviour being somewhat unexpected
                             * to most software. So for now, for the K95 terminal
                             * type only, we do not preserve the intensity bit */
                            if (ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                l = sgrcols[pn[j] - 30];
                                if (decscnm) {
                                    attribute = cell_video_attr_set_bg_color(attribute, l);

                                    if ( ISSCO(tt_type_mode) ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_bg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_bg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#endif
                                    }
                                } else {
                                    attribute = cell_video_attr_set_fg_color(attribute, l);

                                    if ( ISSCO(tt_type_mode) ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_fg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_fg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#endif
                                    }
                                }
                            } else {
                                /* Select foreground color, preserving the intensity*/

                                /* Commented out to suppress unreachable code
                                 * compile warning. Not sure why the ISQANSI
                                 * branch is disabled -- DG
                                if ( 0 && ISQANSI(tt_type_mode) )
                                    l = pn[j] - 30;
                                else */
                                    l = sgrcols[pn[j] - 30];
                                if (decscnm) {
                                    attribute = cell_video_attr_set_3bit_bg_color(attribute, l);

                                    if ( ISSCO(tt_type_mode) ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_3bit_bg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_3bit_bg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_3bit_bg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_3bit_fg_color(reverseattribute, l);
#endif
                                    }
                                } else {
                                    attribute = cell_video_attr_set_3bit_fg_color(attribute, l);

                                    if ( ISSCO(tt_type_mode) ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_3bit_fg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_3bit_fg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_3bit_fg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_3bit_bg_color(reverseattribute, l);
#endif
                                    }
                                }
                            }
                            break;
						case 48:    /* 48 - Extended color - background */
                        case 38:    /* 38 - Extended Color */
									/* 38 - Enable underline option (for what terminal? linux console before 3.16 probably) */
						    if (ISXTERM(tt_type_mode) || ISK95(tt_type_mode) ||
						        ISLINUX(tt_type_mode) || ISANSI(tt_type_mode)) {
						        attribute = sgr_38_48(pn, pe, k, &j, pn_pe_start,
						            pn_pe_count, TRUE, attribute);
						    }
                            break;

                        case 39:  /* disable underline option */
                            /* Supported by SCO ANSI */
                            /* QANSI - restore fg color saved with */
                            /* CSI = Pn F                          */
                            if ( !sgrcolors )
                                break;

                            if (decscnm) {
#ifdef CK_COLORS_24BIT
								if (!cell_video_attr_bg_is_indexed(defaultattribute)) {
									/* Background has an RGB color */
									int r, g, b;
									r = cell_video_attr_bg_rgb_r(defaultattribute);
									g = cell_video_attr_bg_rgb_g(defaultattribute);
									b = cell_video_attr_bg_rgb_b(defaultattribute);
									attribute = cell_video_attr_set_bg_rgb(attribute, r, g, b);
								} else
#endif
								{   /* Else background has an indexed color */
	                                /* Copy the 3-bit background color from defaultattribute
	                                 * to attribute */

	                                int def_bg;

	                                /* Get the 3-bit default BG color*/
	                                def_bg = cell_video_attr_background(defaultattribute);

	                                /* only try to preserve the intensity bit if the
	                                 * saved color is within the 16-color range */
	                                if (def_bg < 16) {
	                                    def_bg &= 0x07;
	                                    attribute = cell_video_attr_set_3bit_bg_color(attribute, def_bg);
	                                } else {
	                                    attribute = cell_video_attr_set_bg_color(attribute, def_bg);
	                                }
								}
                            } else {
#ifdef CK_COLORS_24BIT
								if (!cell_video_attr_fg_is_indexed(defaultattribute)) {
									/* Foreground has an RGB color */
									int r, g, b;
									r = cell_video_attr_fg_rgb_r(defaultattribute);
									g = cell_video_attr_fg_rgb_g(defaultattribute);
									b = cell_video_attr_fg_rgb_b(defaultattribute);
									attribute = cell_video_attr_set_fg_rgb(attribute, r, g, b);
								} else
#endif
								{   /* Else foreground has an indexed color */
	                                int def_bg = cell_video_attr_foreground(defaultattribute);
	                                /* only try to preserve the intensity bit if the
	                                 * saved color is within the 16-color range */
	                                if (def_bg < 16) {
	                                    def_bg &= 0x07;
	                                    attribute = cell_video_attr_set_3bit_fg_color(attribute, def_bg);
	                                } else {
	                                    attribute = cell_video_attr_set_fg_color(attribute, def_bg);
                                	}
								}
                            }
                            break;
                        case 40:
                        case 41:
                        case 42:
                        case 43:
                        case 44:
                        case 45:
                        case 46:
                        case 47:
                            /* Select background color */
                            if ( !sgrcolors )
                                break;

                            /* See comment for Select foreground color */
                            if (ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                                l = sgrcols[pn[j] - 40];
                                if (!decscnm) {
                                    attribute = cell_video_attr_set_bg_color(attribute, l);

                                    if ( tt_type_mode == TT_SCOANSI ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_bg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_bg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#endif
                                    }
                                } else {
                                    attribute = cell_video_attr_set_fg_color(attribute, l);

                                    if ( tt_type_mode == TT_SCOANSI ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_fg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_fg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#endif
                                    }
                                }
                            } else {
                                /* Commented out to suppress unreachable code
                                 * compile warning. Not sure why the ISQANSI
                                 * branch is disabled -- DG
                                if ( 0 && ISQANSI(tt_type_mode) )
                                    l = pn[j] - 40;
                                else */
                                    l = sgrcols[pn[j] - 40];
                                if (!decscnm) {
                                    attribute = cell_video_attr_set_3bit_bg_color(attribute, l);

                                    if ( tt_type_mode == TT_SCOANSI ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_3bit_bg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_3bit_bg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_3bit_bg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_3bit_fg_color(reverseattribute, l);
#endif
                                    }
                                } else {
                                    attribute = cell_video_attr_set_3bit_fg_color(attribute, l);

                                    if ( tt_type_mode == TT_SCOANSI ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_3bit_fg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_3bit_fg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_3bit_fg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_3bit_bg_color(reverseattribute, l);
#endif
                                    }
                                }
                            }
                            break;
                        case 49:
                            /* Supported by SCO ANSI */
                            /* QANSI - restore bg color saved with */
                            /* CSI = Pn G                          */
                            if ( !sgrcolors )
                                break;

                            if (!decscnm) {
#ifdef CK_COLORS_24BIT
								if (!cell_video_attr_bg_is_indexed(defaultattribute)) {
									/* Background has an RGB color */
									int r, g, b;
									r = cell_video_attr_bg_rgb_r(defaultattribute);
									g = cell_video_attr_bg_rgb_g(defaultattribute);
									b = cell_video_attr_bg_rgb_b(defaultattribute);
									attribute = cell_video_attr_set_bg_rgb(attribute, r, g, b);
								} else
#endif
								{   /* Else background has an indexed color */
            	                    int def_bg;

        	                        /* Get the 3-bit default BG color*/
    	                            def_bg = cell_video_attr_background(defaultattribute);

                	                /* only try to preserve the intensity bit if the
            	                     * saved color is within the 16-color range */
        	                        if (def_bg < 16) {
    	                                def_bg &= 0x07;
	                                    attribute = cell_video_attr_set_3bit_bg_color(attribute, def_bg);
                                	} else {
                                    	attribute = cell_video_attr_set_bg_color(attribute, def_bg);
                                	}
								}
                            } else {
#ifdef CK_COLORS_24BIT
								if (!cell_video_attr_fg_is_indexed(defaultattribute)) {
									/* Foreground has an RGB color */
									int r, g, b;
									r = cell_video_attr_fg_rgb_r(defaultattribute);
									g = cell_video_attr_fg_rgb_g(defaultattribute);
									b = cell_video_attr_fg_rgb_b(defaultattribute);
									attribute = cell_video_attr_set_fg_rgb(attribute, r, g, b);
								} else
#endif
								{   /* Else foreground has an indexed color */
                        	        int def_bg = cell_video_attr_foreground(defaultattribute);

                    	            /* only try to preserve the intensity bit if the
                	                 * saved color is within the 16-color range */
            	                    if (def_bg < 16) {
        	                            def_bg &= 0x07;
    	                                attribute = cell_video_attr_set_3bit_fg_color(attribute, def_bg);
	                                } else {
                                    	attribute = cell_video_attr_set_fg_color(attribute, def_bg);
                                	}
								}
                            }
                            break;
                        case 50:
                            if ( IS97801(tt_type_mode) ) {
                                /* Save Attributes */
                                /* When the "save attributes" command is issued,  */
                                /* all attributes then in effect for the entire   */
                                /* screen are stored.  These attributes will then */
                                /* apply to any new display data (without SGR com-*/
                                /* mand sequences) output to the screen.          */
                                /* The stored attributes can be returned to normal*/
                                /* by commands such as "erase in display with     */
                                /* blanks/NULs; clear attributes". */
                                break;
                            } else if ( ISSCO(tt_type_mode) ) {
                                /*
                                Reset to the original color pair. In backwards
                                compatibility mode, set the normal attribute to white
                                text on a black background, and reverse video to black
                                text on a white background.  In the default (new) mode,
                                set the current attribute according to the current mode
                                and the current values for reverse, normal or graphics
                                */
                            }
                            break;
                        case 51:
                            if ( ISSCO(tt_type_mode) ) {
                                /*
                                Resets all colors to the system default of gray for the
                                foreground and reverse background, and black for the
                                background and reverse foreground.  Only valid in new
                                mode.
                                */
                                break;
                            }
                        case 90: /* Colors */
                        case 91:
                        case 92:
                        case 93:
                        case 94:
                        case 95:
                        case 96:
                        case 97:
                            /* Select foreground color (8-bit high) */
                            if ( !sgrcolors )
                                break;
                            /* Disabled to suppress unreachable code compile
                             * warning. Not sure why the ISQANSI branch is
                             * disabled -- DG
                            if ( 0 && ISQANSI(tt_type_mode) )
                                l = pn[j] - 90;
                            else */
                                l = sgrcols[pn[j] - 90];
                            l += 8;     /* 8th bit high */
                            if (decscnm
#ifdef COMMENT
                                 && !attrib.reversed ||
                                 !decscnm && attrib.reversed
#endif
                                 ) {
                                attribute = cell_video_attr_set_bg_color(attribute, l);

                                if ( tt_type_mode == TT_SCOANSI ) {
                                    /* set the default attribute as well */
                                    defaultattribute = cell_video_attr_set_bg_color(defaultattribute, l);

                                    graphicattribute = cell_video_attr_set_bg_color(graphicattribute, l);
#ifdef COMMENT
                                    reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#else
                                    reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#endif
                                }
                                } else {
                                    attribute = cell_video_attr_set_fg_color(attribute, l);

                                    if ( tt_type_mode == TT_SCOANSI ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_fg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_fg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#endif
                                    }
                                }
                            break;
                        case 100:
                        case 101:
                        case 102:
                        case 103:
                        case 104:
                        case 105:
                        case 106:
                        case 107:
                            /* Select background color (8-bit high) */
                            if ( !sgrcolors )
                                break;

                            /* Commented otu to suppress unreachable code
                             * compile warning. Not sure why the ISQANSI
                             * branch is disabled -- DG
                            if ( 0 && ISQANSI(tt_type_mode) )
                                l = pn[j] - 100;
                            else */
                                l = sgrcols[pn[j] - 100];
                            l += 8;     /* 8th bit high */
                            if (!decscnm
#ifdef COMMENT
                                 && !attrib.reversed ||
                                 decscnm && attrib.reversed
#endif
                                ) {
                                attribute = cell_video_attr_set_bg_color(attribute, l);

                                if ( tt_type_mode == TT_SCOANSI ) {
                                    /* set the default attribute as well */
                                    defaultattribute = cell_video_attr_set_bg_color(defaultattribute, l);

                                    graphicattribute = cell_video_attr_set_bg_color(graphicattribute, l);
#ifdef COMMENT
                                    reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#else
                                    reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#endif
                                }
                                } else {
                                    attribute = cell_video_attr_set_fg_color(attribute, l);

                                    if ( tt_type_mode == TT_SCOANSI ) {
                                        /* set the default attribute as well */
                                        defaultattribute = cell_video_attr_set_fg_color(defaultattribute, l);

                                        graphicattribute = cell_video_attr_set_fg_color(graphicattribute, l);
#ifdef COMMENT
                                        reverseattribute = cell_video_attr_set_fg_color(reverseattribute, l);
#else
                                        reverseattribute = cell_video_attr_set_bg_color(reverseattribute, l);
#endif
                                    }
                                }
                            break;
                        default:
                            break;
                        } /* switch...*/
					} /* for... */

					if (ISVT525(tt_type_mode) && decstglt == DECSTGLT_ALTERNATE) {
						/* The VT525 apparently assigns alternate colour palette
						 * indicies to the default attribute after processing SGR
						 * sequences when in Alternate Color Mode. It doesn't
						 * actually *obey* colour attributes while in this mode,
						 * but the effect should be visible in DECRQCRA and also
						 * after switching out of Alternate Color Mode */
						/* TODO: Confirm if this should happen on *all* SGR
						 * 		 sequences, or just when, certain attribute are
						 * 		 updated */
						int idx = get_alternate_color_index(
							vtattrib_to_int(attrib));
#ifndef KUI
            			attribute = cell_video_attr_to_palette(
							CK_PALETTE_VT525_A, decatc_colors[idx]);
#else

            			attribute = decatc_colors[idx];
#endif /* KUI */
						reverseattribute = byteswapcolors(attribute);
					}
                } /* SGR */
                break;
            case 'r':   /* Proprietary */
                if ( ISH19(tt_type) ) {
                    /* Set Baud Rate to pn[1] */
                    break;
                }
                else if ( ISSUN(tt_type_mode) ) {
                    /* 
                    ESC[#r      Set scrolling (SUNSCRL)
                    Takes one parameter, #  (default  0).   Sets  to  #  an
                    internal  register  which determines how many lines the
                    screen scrolls up when a  line-feed  function  is  per-
                    formed with the cursor on the bottom line.  A parameter
                    of 2 or 3 introduces a small amount of ``jump'' when  a
                    scroll  occurs.   A  parameter  of 34 clears the screen
                    rather than scrolling.  The initial  setting  is  1  on
                    reset.

                    A parameter of zero initiates ``wrap mode'' instead  of
                    scrolling.   In  wrap mode, if a linefeed occurs on the
                    bottom line, the cursor  goes  to  the  same  character
                    position  in  the  top  line  of  the screen.  When any
                    linefeed occurs, the line that the cursor moves  to  is
                    cleared.   This  means  that  no scrolling ever occurs.
                    `ESC [ 1 r' exits back to scroll mode.

                    For more information, see the description of the  Line-
                    feed (CTRL-J) control function above.
                    */
                }
                else if ( ansiext && ISSCO(tt_type_mode) ) {
					vscrn_setc_page_margin_top(VTERM, 1);
                    vscrn_setc_page_margin_bot(VTERM, VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0));
                    vscrn_setc_page_margin_left(VTERM, 1);
                    vscrn_setc_page_margin_right(VTERM, VscrnGetWidth(VTERM));
                    break;
                } else if ( private ) {
                    /* Restore Modes */
                    if ( ISHFT(tt_type_mode) ) {
                        for (j = 1; j <= k; ++j) /* Go thru all Pn's */
                            switch ((pn[j])) {   /* This one... */
                            default:
                                break;
                            }
                    }
                }
                else {
                    /*  DECSTBM - Set margin (scrolling region) */
                    int h = VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0);
                    int w = VscrnGetWidth(VTERM);

                    if ((k < 2) || (pn[2] == 0))
                        pn[2] = h;

                    /* for SCO */
                    if ((k < 3) || (pn[3] == 0))
                        pn[3] = 1;

                    if ((k < 4) || (pn[4] == 0))
                        pn[4] = w;

                    if (pn[1] == 0)
                        pn[1] = 1;

                    /* The 97801 allows the bottom margin include the */
                    /* status line even when it is separated from the */
                    /* main display area.                             */
                    if ( IS97801(tt_type_mode) &&
                         decssdt == SSDT_HOST_WRITABLE )
                        h++;

                    if  ((pn[1] > 0) &&
                         (pn[1] < pn[2]) &&
                         (pn[2] <= h) &&
                         (pn[3] < pn[4]) &&
                         (pn[4] <= w))
                    {
                        setmargins(pn[1], pn[2]);
                        if ( ISSCO(tt_type_mode) ) {
                            vscrn_setc_page_margin_left(VTERM, pn[3]);
                            vscrn_setc_page_margin_right(VTERM, pn[4]);
                            lgotoxy(VTERM, relcursor ? vscrn_c_page_margin_left(VTERM) : 1,
                                     relcursor ? vscrn_c_page_margin_bot(VTERM) : 1);
                        } else if ( !IS97801(tt_type_mode) ) {
                            home_cursor(vmode);
                        }
                    }
                    else if (!ISSCO(tt_type_mode)) {
                        if ( pn[1] > 0 &&
                            pn[1] <= VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) )
                            pn[2] = VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) ;
                        setmargins(pn[1], pn[2]);
                        if ( !IS97801(tt_type_mode) ) {
                            home_cursor(vmode);
                        }
                    }
                    break;
                }
                break;
            case 'J':
                if ( ansiext && private ) {
                    if ( ISBA80(tt_type_mode) ) {
                        /* Screen Saver On */
                    }
                }
                else if ( ansiext ) {
                    /* ANSI - Set Graphic Foreground Color */
                    if ( ISANSI(tt_type_mode) ) {
                        /* pn[1] contains new color */
                        l = pn[1];
                        graphicattribute = cell_video_attr_set_fg_color(graphicattribute, l);
                    }
                }
                else if ( private == TRUE ) {
                    /* Selective clear screen - DECSED */
                    if ( ISVT220(tt_type_mode) ) {
                        switch ((pn[1])) {
                            /* Selective clear to end of screen */
                        case 0:
                            selclreoscr_escape(VTERM,SP);
                            break;
                            /* Selective clear to beginning */
                        case 1:
                            selclrboscr_escape(VTERM,SP);
                            break;
                            /* Selective clear whole screen */
                        case 2:
                            {
                                /* Cursor does not move */
                                if ( decsasd == SASD_STATUS ) {
                                    selclrscreen(VSTATUS,SP);
                                }
                                else {
                                    selclrscreen(VTERM,SP);
                                }
                            }
                            break;
                        case 3: if (ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                            /* Selective Erase Scrollback (xterm) */
                            /* While the xterm docuemntation says this is
                             * selective erase, in xterm-409b it is an
                             * unselective erase of everything in scrollback */
                            clearscrollback(VTERM, TRUE);
                            break;
                        }
                        default:
                            break;
                        }
                    }

                    if (tt_type != TT_VT100 && tt_type != TT_VT102) {
                        /* The VT10x and only the VT10x do not clear the LCF on
                         * erase display. The VT220 and VT520 emulating a VT100
                         * do. */
                        wrapit = FALSE;
                    }
                } else {
                    /* Erase in Display (ED) */
                    /* ??? For the 97801, the called functions must be */
                    /* recoded to only clear the current scroll region */
                    /* with both vertical and horizontal boundaries.   */
                    if ( IS97801(tt_type_mode) ) {
                        /* ignored if outside scroll region */
                        if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                            wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                            break;
                    }
                    switch ((pn[1])) {
                    case 0:
                        /* Clear to end of screen w/SP */
                        /* Clear Attributes */
                        if ( IS97801(tt_type_mode) )
                            clreoreg_escape(VTERM,SP);
                        else
                            clreoscr_escape(VTERM,SP);
                        break;
                    case 1:
                        /* Clear to beginning w/SP */
                        /* Clear Attributes */
                        if ( IS97801(tt_type_mode) )
                            clrboreg_escape(VTERM,SP);
                        else
                            clrboscr_escape(VTERM,SP);
                        break;
                    case 2:
                        /* Clear whole screen w/SP */
                        /* Clear Attributes */
                        /* DEC ... */
                        if ( !ISANSI(tt_type_mode) ) {
                            /* Cursor does not move */
                            if ( decsasd == SASD_STATUS ) {
                                clrscreen(VSTATUS,SP);
                            }
                            else {
                                if ( IS97801(tt_type_mode) )
                                    clrregion(VTERM,SP);
                                else
                                    clrscreen(VTERM,SP);
                            }
                        } else { /* ANSI homes the cursor */
                            clrscreen(VTERM,SP);
                            lgotoxy(VTERM,1,1);       /* and home the cursor */
                        }
                        break;
                    case 3:
                        /* Clear to end of screen w/NUL */
                        /* Clear Attributes */
                        if ( IS97801(tt_type_mode) ) {
                            clreoreg_escape(VTERM,NUL);
                        }
                        else if (ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                            /* Erase Scrollback (xterm) */
                            clearscrollback(VTERM, TRUE);
                        }
                        break;
                    case 4:
                        /* Clear to beginning w/NUL */
                        /* Clear Attributes */
                        if ( IS97801(tt_type_mode) ) {
                            clrboreg_escape(VTERM,NUL);
                        }
                        break;
                    case 5:
                        /* Clear whole screen w/NUL */
                        /* Clear Attributes */
                        /* DEC ... */
                        /* Cursor does not move */
                        if ( IS97801(tt_type_mode) ) {
                            if ( decsasd == SASD_STATUS ) {
                                clrscreen(VSTATUS,NUL);
                            }
                            else {
                                clrregion(VTERM,NUL);
                            }
                        }
                        break;
                    case 6:
                        /* Clear to end of screen w/SP */
                        /* Preset with the last valid attribute */
                        /* (if attributes are not stored) */
                        if ( IS97801(tt_type_mode) ) {
                            clreoreg_escape(VTERM,SP);
                        }
                        break;
                    case 7:
                        /* Clear to beginning w/SP */
                        /* Preset with the last valid attribute */
                        /* (if attributes are not stored) */
                        if ( IS97801(tt_type_mode) ) {
                            clrboreg_escape(VTERM,SP);
                        }
                        break;
                    case 8:
                        /* Clear whole screen w/SP */
                        /* Preset with the last valid attribute */
                        /* (if attributes are not stored) */
                        if ( IS97801(tt_type_mode) ) {
                            if ( decsasd == SASD_STATUS ) {
                                clrscreen(VSTATUS,SP);
                            }
                            else {
                                clrregion(VTERM,SP);
                            }
                        }
                        break;
                    case 9:
                        /* Clear to end of screen w/NUL */
                        /* Preset with the last valid attribute */
                        /* (if attributes are not stored) */
                        if ( IS97801(tt_type_mode) ) {
                            clreoreg_escape(VTERM,NUL);
                        }
                        break;
                    case 10:
                        /* Clear to beginning w/NUL */
                        /* Preset with the last valid attribute */
                        /* (if attributes are not stored) */
                        if ( IS97801(tt_type_mode) ) {
                            clrboreg_escape(VTERM,NUL);
                        }
                        break;
                    case 11:
                        /* Clear whole screen w/NUL */
                        /* Preset with the last valid attribute */
                        /* (if attributes are not stored) */
                        if ( IS97801(tt_type_mode) ) {
                            if ( decsasd == SASD_STATUS ) {
                                clrscreen(VSTATUS,NUL);
                            }
                            else {
                                clrregion(VTERM,NUL);
                            }
                        }
                        break;
                    case 12:
                        /* Clear to end of screen w/SP */
                        /* Preserve attributes */
                        if ( IS97801(tt_type_mode) ) {
                            clreoreg_escape(VTERM,SP);
                        }
                        break;
                    case 13:
                        /* Clear to beginning w/SP */
                        /* Preserve attributes */
                        if ( IS97801(tt_type_mode) ) {
                            clrboreg_escape(VTERM,SP);
                        }
                        break;
                    case 14:
                        /* Clear whole screen w/SP */
                        /* Preserve attributes */
                        if ( IS97801(tt_type_mode) ) {
                            if ( decsasd == SASD_STATUS ) {
                                clrscreen(VSTATUS,SP);
                            }
                            else {
                                clrregion(VTERM,SP);
                            }
                        }
                        break;
                    case 15:
                        /* Clear to end of screen w/NUL */
                        /* Preserve attributes */
                        if ( IS97801(tt_type_mode) ) {
                            clreoreg_escape(VTERM,NUL);
                        }
                        break;
                    case 16:
                        /* Clear to beginning w/NUL */
                        /* Preserve attributes */
                        if ( IS97801(tt_type_mode) ) {
                            clrboreg_escape(VTERM,NUL);
                        }
                        break;
                    case 17:
                        /* Clear whole screen w/NUL */
                        /* Preserve attributes */
                        if ( IS97801(tt_type_mode) ) {
                            if ( decsasd == SASD_STATUS ) {
                                clrscreen(VSTATUS,NUL);
                            }
                            else {
                                clrregion(VTERM,NUL);
                            }
                        }
                        break;
                    default:
                        break;
                    }

                    if (tt_type != TT_VT100 && tt_type != TT_VT102) {
                        /* The VT10x and only the VT10x do not clear the LCF on
                         * erase line. The VT220 and VT520 emulating a VT100
                         * do. */
                        wrapit = FALSE;
                    }
                }
                break;
			case 'U': /* NP - Next Page */
				if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
					if (!on_alternate_buffer(VTERM)) {
						next_page(VTERM, pn[1]);
						lgotoxy(VTERM,1,1);
					}
				}
				break;
            case 'V': /* PP - Preceding Page */
				if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
					if (!on_alternate_buffer(VTERM)) {
						previous_page(VTERM, pn[1]);
						lgotoxy(VTERM,1,1);
					}
                } else if (ISSCO(tt_type_mode)) {
                    /* Erase in Region (ER) */
                    switch ((pn[1])) {
                    case 0:
                        /* Clear to end of screen w/SP */
                        /* Clear Attributes */
                        clreoreg_escape(VTERM,SP);
                        break;
                    case 1:
                        /* Clear to beginning w/SP */
                        /* Clear Attributes */
                        clrboreg_escape(VTERM,SP);
                        break;
                    case 2:
                        /* Clear whole region w/SP */
                        /* Clear Attributes */
                        /* DEC ... */
                        clrregion(VTERM,SP);
                        break;
                    default:
                        break;
                    }
                }
                break;
            case 'v':   /* Proprietary */
                if ( ISAAA(tt_type_mode) ) {
                    /* zSRC - Start Remote Copy */
                    break;
                } else if ( IS97801(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 5:
                        /* Switch within G0 (national/international, 7-bit mode) */
                        if ( sni_bitmode == 7 )
                            SNI_chcode(!sni_chcode);
                        break;
                    case 7:
                        /* Full screen mode off */
                        break;
                    case 8:
                        /* Fill scroll area with chracters (diagnostics) */
                        break;
                    case 9:
                        /* Output entire character generator */
                        break;
                    case 10:
                        /* Disable CH.CODE key (7-bit mode) */
                        sni_chcode_7 = 0;
                        break;
                    case 11:
                        /* Enable CH.CODE key (7-bit mode) */
                        sni_chcode_7 = 1;
                        break;
                    case 13: {
                        /* Query current code table */
                        /* 0 - SI: G0FEST active */
                        /* 1 - SI: G0 active     */
                        /* 2 - SO: G0FEST activ  */
                        /* 3 - SO: G0 active     */

                        char chtable[9];
                        char status;
                        if ( GL == &G[0] )
                            status = sni_chcode ? '1' : '0';
                        else
                            status = sni_chcode ? '3' : '2';
                        if ( send_c1 )
                            sprintf(chtable,"%c13v%c%c",_DCS,status,_ST8);
                        else
                            sprintf(chtable,"%cP13v%c%c\\",ESC,status,ESC);
                        sendchars(chtable,strlen(chtable));
                        break;
                    }
                    case 20:
                        /* Switch to alternative key assignment table (8-bit CH.CODE) */
                        if ( sni_bitmode == 8 )
                            SNI_chcode(!sni_chcode);
                        break;
                    case 21: {
                        /* Query current key assignment table (CH.CODE status, 8-bit mode) */
                        char chtable[9];
                        char status;
                        status = sni_chcode ? '1' : '0';
                        if ( send_c1 )
                            sprintf(chtable,"%c21v%c%c",_DCS,status,_ST8);
                        else
                            sprintf(chtable,"%cP21v%c%c\\",ESC,status,ESC);
                        sendchars(chtable,strlen(chtable));
                        break;
                    }
                    case 22:
                        /* Disable CH.CODE key (8-bit mode) */
                        sni_chcode_8 = 0;
                        break;
                    case 23:
                        /* Enable CH.CODE key (8-bit mode) */
                        sni_chcode_8 = 1;
                        break;
                    }
                }
                break;
            case 'w': /* Proprietary */
                if ( ISAAA(tt_type_mode) ) {
                    /* zSPF - Set Print Format Pn1;Pn2;Pn3
                     * Pn1 - Printed Lines (per page) 1 - 126
                     * Pn2 - Total Lines (per page) 1 - 126
                     * Pn3 - Left Margin 0 - 254
                     */
                } 
                else if ( ISHFT(tt_type_mode) ) {
                    /* vt raw keyboard input */
                    ;
                }
                else if ( IS97801(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 0:     /* Transmit keylock switch status */
                        break;
                    case 1:     /* Reinitialize character generator */
                        break;
                    }
                }
                else if ( ISWY370(tt_type_mode) )
                {
                    /* All sorts of color controls */
                    switch ( pn[1] ) {
                        /* 0-47 - Defining Color Associations */
                    case 48:
                        /* Select Foreground Color */
                        break;
                    case 49:
                        /* Select Background Color */
                        /* Sets border color to Bg Color */
                        break;
                    case 50:
                        /* Restore Foreground and Background colors */
                        /* sets border color to bg color */
                        break;
                    case 51:
                        /* Select border color */
                        break;
                    case 52:
                        /* Select cursor color */
                        break;
                    case 54:
                        /* Select user status line attrs/colors */
                        break;
                    case 55:
                        /* Select system status line attrs/colors */
                        break;
                    case 56:
                        /* Select replacement chars attrs/colors */
                        break;
                    case 57:
                        /* Select nonerasable chars attrs/colors */
                        break;
                    case 60:
                        /* Restore default color index values */
                        break;
                    case 61:
                        /* Assign current char fg color */
                        /* Turns on color index mode    */
                        break;
                    case 62:
                        /* Assign current char bg color */
                        /* sets border color to bg color */
                        break;
                    case 63:
                        /* Turn color index mode on/off */
                        break;
                    case 64:
                        /* Change current nonerasable char */
                        /* foreground color                */
                        break;
                    case 65:
                        /* Change current nonerasable char */
                        /* background color                */
                        break;
                    case 66:
                        /* Redefine color index value */
                        break;
                    default:
                        break;
                    }
                }
                break;
            case 'K':
                if ( ansiext )
                {
                    /* ANSI - Set Graphic Background Color */
                    if ( ISANSI(tt_type_mode) ) {
                        /* pn[1] contains new color */
                        l = pn[1];
                        graphicattribute = cell_video_attr_set_bg_color(graphicattribute, l);
                    }
                    else if ( ISBA80(tt_type_mode) ) {
                        /* Begin Reading Function Labels */
                        ba80_fkey_read = -1;
                    }
                }
                else if ( private == TRUE ) {
                    /* Selective clear line - DECSEL */
                    if ( ISVT220(tt_type_mode) ) {
                        switch ((pn[1])) {
                            /* Selective clear to end of line; clear attributes */
                        case 0:
                            selclrtoeoln(VTERM,SP);
                            break;
                            /* Selective clear to beginning; clear attributes */
                        case 1:
                            selclrbol_escape(VTERM,SP);
                            break;
                            /* Selective clear whole cursor line; clear attributes */
                        case 2:
                            selclrline_escape(VTERM,SP);
                            break;
                        default:
                            break;
                        }
                    }
                } else {
                    /* Erase line (EL) */
                    switch ((pn[1])) {
                    case 0:
                        /* Clear to end of line; clear attributes */
                        clrtoeoln(VTERM,SP);
                        break;
                    case 1:
                        /* Clear to beginning; clear attributes */
                        clrbol_escape(VTERM,SP);
                        break;
                    case 2:
                        /* Clear whole cursor line; clear attributes */
                        clrline_escape(VTERM,SP);
                        break;
                    case 3:
                        /* SNI 97801 */
                        /* Erase with NULs to EOL */
                        /* Clear attributes */
                        clrtoeoln(VTERM,NUL);
                        break;
                    case 4:
                        /* SNI 97801 */
                        /* Erase with NULs to BOL */
                        /* Clear attributes */
                        clrbol_escape(VTERM,NUL);
                        break;
                    case 5:
                        /* SNI 97801 */
                        /* Erase with NULs entire line */
                        /* Clear attributes */
                        clrline_escape(VTERM,NUL);
                        break;
                    case 6:
                        /* SNI 97801 */
                        /* Erase with SP to EOL */
                        /* Preset with the last valid SGR attribute */
                        /* (if attributes are not stored) */
                        clrtoeoln(VTERM,SP);
                        break;
                    case 7:
                        /* SNI 97801 */
                        /* Erase with SP to BOL */
                        /* Preset with the last valid SGR attribute */
                        /* (if attributes are not stored) */
                        clrbol_escape(VTERM,SP);
                        break;
                    case 8:
                        /* SNI 97801 */
                        /* Erase with SP entire line */
                        /* Preset with the last valid SGR attribute */
                        /* (if attributes are not stored) */
                        clrline_escape(VTERM,SP);
                        break;
                    case 9:
                        /* SNI 97801 */
                        /* Erase with NUL to EOL */
                        /* Preset with the last valid SGR attribute */
                        /* (if attributes are not stored) */
                        clrtoeoln(VTERM,NUL);
                        break;
                    case 10:
                        /* SNI 97801 */
                        /* Erase with NUL to BOL */
                        /* Preset with the last valid SGR attribute */
                        /* (if attributes are not stored) */
                        clrbol_escape(VTERM,NUL);
                        break;
                    case 11:
                        /* SNI 97801 */
                        /* Erase with NUL entire line */
                        /* Preset with the last valid SGR attribute */
                        /* (if attributes are not stored) */
                        clrline_escape(VTERM,NUL);
                        break;
                    case 12:
                        /* SNI 97801 */
                        /* Erase with SP to EOL */
                        /* Preserve attributes */
                        clrtoeoln(VTERM,SP);
                        break;
                    case 13:
                        /* SNI 97801 */
                        /* Erase with SP to BOL */
                        /* Preserve attributes */
                        clrbol_escape(VTERM,SP);
                        break;
                    case 14:
                        /* SNI 97801 */
                        /* Erase with SP entire line */
                        /* Preserve attributes */
                        clrline_escape(VTERM,SP);
                        break;
                    case 15:
                        /* SNI 97801 */
                        /* Erase with NUL to EOL */
                        /* Preserve attributes */
                        clrtoeoln(VTERM,NUL);
                        break;
                    case 16:
                        /* SNI 97801 */
                        /* Erase with NUL to BOL */
                        /* Preserve attributes */
                        clrbol_escape(VTERM,NUL);
                        break;
                    case 17:
                        /* SNI 97801 */
                        /* Erase with NUL entire line */
                        /* Preserve attributes */
                        clrline_escape(VTERM,NUL);
                        break;
                    default:
                        break;
                    }

                    if (tt_type != TT_VT100 && tt_type != TT_VT102) {
                        /* The VT10x and only the VT10x do not clear the LCF on
                         * erase line. The VT220 and VT520 emulating a VT100
                         * do. */
                        wrapit = FALSE;
                    }
                }
                break;
            case 'L':
                if ( ISSCO(tt_type_mode) && ansiext ) {
                    /* SCO - Set Emulation Feature */
                    switch ( pn[1] ) {
                    case 0: /* New regions filled with the current attribute (default) */
                        break;
                    case 1: /* New regions filled with the normal attribute */
                        break;
                    case 2: /* Disable iBCS2 compliance (default) */
                        break;
                    case 3: /* Enable iBCS2 compliance */
                        break;
                    case 4: /* Disable ANSI SGR0 interpretation (default) */
                        break;
                    case 5: /* Enable ANSI SGR0 interpretation */
                        break;
                    case 6: /* Disable backwards compatibility mode (default) */
                        scocompat = FALSE;
                        break;
                    case 7: /* Enable backwards compatibility mode (resets margins too) */
                        scocompat = TRUE;
                        break;
                    case 8: /* Cursor motion bound by region (default) */
                        break;
                    case 9: /* Cursor motion unbound */
                        break;
                    case 10: /* Enable 8-bit keyboard meta mode (default) */
                        break;
                    case 11: /* Disable 8-bit keyboard meta mode */
                        break;
                    case 12: /* Disable debugging for this screen (default) */
                        break;
                    case 13: /* Enable debugging for this screen (do not use) */
                        break;
                    case 14: /* Disable global video loop debugging (default) */
                        break;
                    case 15: /* Enable global video loop debugging (do not use) */
                        break;
                    case 16: /* Enable M6845 frame buffer optimization (default) */
                        break;
                    case 17: /* Disable M6845 frame buffer optimization (debugging only) */
                        break;
                    case 20: /* Disable using ESC for meta (high) bit. */
                        break;
                    case 21: /* Enable using ESC for meta (high) bit. */
                        break;
                    default:
                        break;
                    }
                } else if ( ISANSI(tt_type_mode) && ansiext ) {
                    /* ANSI - Set Fill (Erase?) mode */
                    if ( !pn[1] )
                        /* use current color */
                        erasemode = FALSE ;
                    else
                        /* use normal color */
                        erasemode = TRUE ;
                }
                else {
                    if ( ISVT102(tt_type_mode) ||
                         ISANSI(tt_type_mode)) {
                        /* IL - Insert lines */
                        /* DEC STD 070 says: "IL is ignored if the active
                         * position is outside the scroll area". So I'm not sure
                         * why this was previously restricted to SNI-97801 - did
                         * some earlier VT model not follow this rule?
                         *      - DG, 2026-03-30                            */
                         /*if ( IS97801(tt_type_mode) ) {*/
                            /* ignored if outside scroll region */
                            if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                                 wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) ||
                                 wherex[VTERM] < vscrn_c_page_margin_left(VTERM) ||
                                 wherex[VTERM] > vscrn_c_page_margin_right(VTERM))
                                break;
                        /*}*/
                        for (i = 1; i <= pn[1]; ++i) {
                            VscrnScrollPage(VTERM,
                                         DOWNWARD,
                                         wherey[VTERM]-1,
                                         vscrn_c_page_margin_bot(VTERM)-1,
                                         vscrn_c_page_margin_left(VTERM)-1,
                                         vscrn_c_page_margin_right(VTERM)-1,
                                         1,
                                         FALSE,
                                         SP,
                                         vscrn_current_page_number(vmode, FALSE) );
                        }
                        wherex[VTERM] = vscrn_c_page_margin_left(VTERM);
                    }
                }
                break;
            case 'M':
                if ( ansiext ) {
                    /* ANSI - Report Color Attributes */
                    if ( ISANSI(tt_type_mode) )
                    {
                        char buf[32] ;

                        /* This really should only return a 16-color value, but
                         * in 256-color builds if a value is outside that range
                         * we'll return it anyway. Its a little unlikely an
                         * application expecting this to return a 16-color value
                         * would go setting colors outside that range.
                         *
                         * In 24-bit RGB builds, if the current value is an RGB
                         * color, we'll convert it to something in the current
                         * palette for return. */

                        switch ( pn[1] ) {
                        case 0: /* Normal */
                        case 2: { /* Graphic - ??? */
                            int fg, bg;

#ifdef CK_COLORS_24BIT
                            if (!cell_video_attr_fg_is_indexed(defaultattribute)) {
                                /* FG is a 24-bit RGB value. Convert it to */
                                fg = nearest_palette_color_rgb(
                                    colorpalette,
                                    cell_video_attr_fg_rgb_r(defaultattribute),
                                    cell_video_attr_fg_rgb_g(defaultattribute),
                                    cell_video_attr_fg_rgb_b(defaultattribute));
                            } else
#endif
                            {
                                fg = cell_video_attr_foreground(defaultattribute);
                            }

#ifdef CK_COLORS_24BIT
                            if (!cell_video_attr_bg_is_indexed(defaultattribute)) {
                                /* FG is a 24-bit RGB value. Convert it to */
                                bg = nearest_palette_color_rgb(
                                    colorpalette,
                                    cell_video_attr_bg_rgb_r(defaultattribute),
                                    cell_video_attr_bg_rgb_g(defaultattribute),
                                    cell_video_attr_bg_rgb_b(defaultattribute));
                            } else
#endif
                            {
                                bg = cell_video_attr_background(defaultattribute);
                            }

                            sprintf(buf,"%d %d\n", fg, bg);
                            break;
                            }
                        case 1: { /* Reverse */
                            int fg, bg;

#ifdef CK_COLORS_24BIT
                            if (!cell_video_attr_bg_is_indexed(defaultattribute)) {
                                /* FG is a 24-bit RGB value. Convert it to */
                                fg = nearest_palette_color_rgb(
                                    colorpalette,
                                    cell_video_attr_bg_rgb_r(defaultattribute),
                                    cell_video_attr_bg_rgb_g(defaultattribute),
                                    cell_video_attr_bg_rgb_b(defaultattribute));
                            } else
#endif
                            {
                                fg = cell_video_attr_background(defaultattribute);
                            }

#ifdef CK_COLORS_24BIT
                            if (!cell_video_attr_fg_is_indexed(defaultattribute)) {
                                /* FG is a 24-bit RGB value. Convert it to */
                                bg = nearest_palette_color_rgb(
                                    colorpalette,
                                    cell_video_attr_fg_rgb_r(defaultattribute),
                                    cell_video_attr_fg_rgb_g(defaultattribute),
                                    cell_video_attr_fg_rgb_b(defaultattribute));
                            } else
#endif
                            {
                                bg = cell_video_attr_foreground(defaultattribute);
                            }

                            sprintf(buf,"%d %d\n", fg, bg);
                            break;
                            }
                        default:
                            *buf = '\0';
                        }

                        if ( *buf )
                            sendcharsduplex( buf, strlen(buf), FALSE);
                    } else if ( ISBA80(tt_type_mode) ) {
                        /* Move to Status Line */
                        setdecssdt( SSDT_HOST_WRITABLE );
                        setdecsasd( SASD_STATUS );
                    }
                }
                else {
                    if ( ISVT102(tt_type_mode) ||
                         ISANSI(tt_type_mode)) {
                        /* DL - Delete lines */
                        if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                             wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) ||
                             wherex[VTERM] < vscrn_c_page_margin_left(VTERM) ||
                             wherex[VTERM] > vscrn_c_page_margin_right(VTERM))
                            break;
                        for (i = 1; i <= pn[1]; ++i) {
                            VscrnScrollPage(VTERM,
                                         UPWARD,
                                         wherey[VTERM] - 1,
                                         vscrn_c_page_margin_bot(VTERM) - 1,
                                         vscrn_c_page_margin_left(VTERM) - 1,
                                         vscrn_c_page_margin_right(VTERM) - 1,
                                         1,
                                         FALSE,
                                         SP,
                                         vscrn_current_page_number(vmode, FALSE));
                        }
                        lgotoxy(VTERM,
                            vscrn_c_page_margin_left(VTERM),
                            wherey[VTERM]);
                    }
                }
                break;
            case '@':   /* (ICH) Insert characters */
                if ( ISVT102(tt_type_mode) ||
                     ISANSI(tt_type_mode) &&
                     private == FALSE &&
                     ansiext == FALSE ) {

                    /* DEC STD 070 says this is ignored if outside the
                     * left/right margins */
                    if ( wherex[VTERM] < cursor_left_margin(VTERM) ||
                         wherex[VTERM] > cursor_right_margin(VTERM))
                        break;

                    blankvcell.c = SP;
                    blankvcell.video_attr = geterasecolor(VTERM);
                    if (pn[1] > cursor_right_margin(VTERM) + 1 -
                         wherex[VTERM])
                        pn[1] = cursor_right_margin(VTERM) + 1 -
                            wherex[VTERM];
                    VscrnScrollRt(VTERM, wherey[VTERM] - 1,
                                   wherex[VTERM] - 1,
                                   wherey[VTERM] - 1,
                                   cursor_right_margin(VTERM) - 1,
                                   pn[1],
                                   blankvcell
                                   );

                    if (tt_type != TT_VT520 && tt_type != TT_VT525 &&
                            tt_type != TT_K95) {
                        /* The VT220 and 420 clear the LCF on ICH. The VT520
                         * does not. */
                        wrapit = FALSE;
                    }
                }
                break;
            case 'N':
                if ( ISHFT(tt_type_mode) || ISLINUX(tt_type_mode) || 
                     ISAAA(tt_type_mode)) {
                    /* EF - Erase Field */
                    int start, end, width;
                    blankvcell.c = ' ' ;
                    blankvcell.video_attr = geterasecolor(VTERM) ;
                    /* TODO: attrib.erased = TRUE; ? */
                    start = end = wherex[VTERM];
                    width = VscrnGetWidth(VTERM);
                    if (start > 1) {
                        do {
                            start--;
                        } while ((htab[start] != 'T') &&
                                  (start >= 2));
                    }
                    if (end < width) {
                        do {
                            end++;
                        } while ((htab[end] != 'T') &&
                                  (end < width));
                    }
                    switch ( pn[1] ) {
                    case 0: /* Erase to End of Field (cursor to tab stop) */
                        for ( i = wherex[VTERM] ; i < end ; i++ ) {
                            VscrnWrtCell(VTERM,
                                          blankvcell,
                                          attrib,
                                          wherey[VTERM]-1,
                                          i);
                        }
                        break;
                    case 1: /* Erase From Field Start (tab stop to cursor) */
                        for ( i = start ; i <= wherex[VTERM] ; i++ ) {
                            VscrnWrtCell(VTERM,
                                          blankvcell,
                                          attrib,
                                          wherey[VTERM]-1,
                                          i);
                        }
                        break;
                    case 2: /* Erase All of Field (tab stop to tab stop) */
                        for ( i = start ; i <= end ; i++ ) {
                            VscrnWrtCell(VTERM,
                                          blankvcell,
                                          attrib,
                                          wherey[VTERM]-1,
                                          i);
                        }
                        break;
                    }
                }
                break;
            case 'O':
                if ( ISBA80(tt_type_mode) && ansiext ) {
                    /* Open Virtual Window */
                    /* Format is CSI = O Pa Pn1[:Pn2][;Pa Pn1[:Pn2]][...] O */
                    /* Pa = 1 - Set Height:Width of virtual window */
                    /* Pa = 2 - Set Row:Column of virtual window in relation to */
                    /*          physical window */
                    /* Pa = 4 - Name of the virtual Window (8 chars) */
                    /*          default are 24:80, name is "Lohn    " */
                }
                else if ( ISHFT(tt_type_mode) ||
                          ISLINUX(tt_type_mode) ||
                          ISAAA(tt_type_mode)) {
                    /* EA - Erase Area */
                    switch ( pn[1] ) {
                    case 0: /* Erase to end of area (line) */
                        clrtoeoln(VTERM,SP);
                        break;
                    case 1: /* Erase from area start (line) */
                        clrbol_escape(VTERM,SP);
                        break;
                    case 2: /* Erase all of area (line) */
                        clrline_escape(VTERM,SP);
                        break;
                    }
                }
                break;
            case 'P':   /* (DCH) DeleteChar */
                if ( (ISVT102(tt_type_mode) ||
                       ISANSI(tt_type_mode)) &&
                     private == FALSE &&
                     ansiext == FALSE ) {

                    /* DEC STD 070 says this is ignored if outside the
                     * left/right margins */
                    if ( wherex[VTERM] < cursor_left_margin(VTERM) ||
                         wherex[VTERM] > cursor_right_margin(VTERM))
                        break;

                    blankvcell.c = SP;
                    blankvcell.video_attr = geterasecolor(VTERM);
                    if (pn[1] > cursor_right_margin(VTERM) + 1 -
                         wherex[VTERM])
                        pn[1] = cursor_right_margin(VTERM) + 1 -
                            wherex[VTERM];
                    VscrnScrollLf(VTERM, wherey[VTERM] - 1,
                                   wherex[VTERM] - 1,
                                   wherey[VTERM] - 1,
                                   cursor_right_margin(VTERM) - 1,
                                   pn[1],
                                   blankvcell
                                   ) ;

                    if (tt_type != TT_VT100 && tt_type != TT_VT102) {
                        /* The VT10x and only the VT10x do not clear the LCF on
                         * DCH. The VT220 and VT520 emulating a VT100 do. */
                        wrapit = FALSE;
                    }
                }
                break;
            case 'Q':   /* SEE - Select Editing Extent */
                if ( ISAAA(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 0:     /* Edit in Page (default) */
                        break;
                    case 1:     /* Edit in Line */
                        break;
                    case 2:     /* Edit in Field (between Tab Stops */
                        break;
                    case 3:     /* Edit in Qualified Area (see DAQ, SPA, EPA) */
                        break;
                    }
                }
                break;
            case 'R':   /* CPR - Cursor Position Report */
                /* Sent to host (see DSR), not processed by terminal */
                break;
            case 'S':
                if ( ansiext ) {
                    if (ISBA80(tt_type_mode)) {
                        /* Return from Status Line */
                        setdecsasd(SASD_TERMINAL);
                    }
                } else {
                    /* (SU) Scroll up-scrolls the characters up */
                    /* n lines.  The bottom n lines are    */
                    /* cleared to blanks (default: n=1). */
                    /* Also (RU) Roll up with SNI 97801 */
                    if ( IS97801(tt_type_mode) ) {
                        /* ignored if outside scroll region */
                        if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                             wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                            break;
                    }
                    if ( pn[1] == 0 )
                        pn[1] = 1 ;
                    else if ( pn[1] > vscrn_c_page_margin_bot(VTERM) )
                        pn[1] = vscrn_c_page_margin_bot(VTERM) ;
                    
                    if ( ISVT320(tt_type_mode) || IS97801(tt_type_mode) ) {
                        if ( sni_scroll_mode ) {
                            VscrnScroll(VTERM, UPWARD,
                                         vscrn_c_page_margin_top(VTERM)-1, wherex[VTERM]-1,
                                         pn[1],
                                         vscrn_c_page_margin_top(VTERM) == 1,
                                         SP,
                                         FALSE);
                        } else { /* Roll Mode */
                            /* TODO:
                             * This is wrong - STD 070 says "This control
                             * affects what is visible on the physical display
                             * only. No movement of data within the Logical
                             * Display occurs. The Active Position does not
                             * change". So the correct behaviour of this would
                             * be more like clicking the up button on the scroll
                             * bar if K95 supported a smaller physical window
                             * than the page (as the console version does for
                             * the horizontal dimension). Though when DECLRMM
                             * is on and the cursor is in the margins, the
                             * behaviour below seems to be correct for the
                             * VT520.
                             */
                            VscrnScrollPage(
                                VTERM,  /* Vscrn */
                                UPWARD, /* Direction */
                                vscrn_c_page_margin_top(VTERM)-1, /* Top */
                                vscrn_c_page_margin_bot(VTERM)-1, /* Bottom */
                                vscrn_c_page_margin_left(VTERM)-1,  /* Left */
                                vscrn_c_page_margin_right(VTERM)-1, /* Right */
                                pn[1], /* Lines */
                                vscrn_c_page_margin_top(VTERM) == 1, /* Save */
                                SP, /* Fill char */
                                vscrn_current_page_number(VTERM, FALSE) /* page */
                                );
                        }
                    }
                    /* No paged memory, so do nothing */
                    else if (ISHFT(tt_type_mode) || ISANSI(tt_type_mode)) {
                            VscrnScroll(VTERM, UPWARD,
                                         0, VscrnGetHeight(VTERM)-((tt_status)?2:1),
                                         pn[1], TRUE, SP, FALSE);
                    }
                }
                break;
            case 's':   /* Proprietary */
                if ( private ) {
                    /* Save Modes */
                    if ( ISHFT(tt_type_mode) ) {
                        for (j = 1; j <= k; ++j) /* Go thru all Pn's */
                            switch ((pn[j])) {   /* This one... */
                            default:
                                break;
                            }
                    }
                } 
                else if ( ISAAA(tt_type_mode) ) {
                    /* zPSH - Push Line */
                }
                else if ( ISSUN(tt_type_mode) ) {
                     /*
                     ESC[s       Reset terminal emulator (SUNRESET)
                     Takes no parameters.   Resets  all  modes  to  default,
                     restores  current  font  from  PROM.  Screen and cursor
                     position are
                     */
                    doreset(1);
                }
                else if ( IS97801(tt_type_mode) ) {
                        switch ( pn[1] ) {
                        case 0: /* Repeat off */
                            break;
                        case 1: /* Repeat on */
                            break;
                        case 2: /* Clicker off */
                            setkeyclick(FALSE);
                            break;
                        case 3: /* Clicker on */
                            setkeyclick(TRUE);
                            break;
                        }
                }
				else if (declrmm &&
				        (decsasd == SASD_TERMINAL || ISXTERM(tt_type_mode)) &&
				        IS_DECLRMM_AVAILABLE(tt_type_mode) ) {
				    /* DECSLRM - Set Left/Right Margins -----------------------
                     * Sets Left/Right margins only if Left/Right Margin Mode is
                     * enabled. The VT520 and VT420 ignore DECSLRM if the cursor
                     * is currently on the status line. This behaviour is not
                     * described by DEC STD-070, and XTERM does not implement
                     * it.
				     */
					int left, right;
					if (k < 1) left = 1;
					else left = pn[1];

					if (left < 1) left = 1;

					if (k < 2) right = VscrnGetWidth(VTERM);
					else right = pn[2];

				    if (left < right && right <= VscrnGetWidth(VTERM))
				    {
				        setlrmargins(left, right);
				        home_cursor(vmode);
				    }
				}
                else if ( ISANSI(tt_type_mode) ||
                            IS97801(tt_type_mode) ||
                            ISSCO(tt_type_mode) ||
                            ISLINUX(tt_type_mode) ||
                            ISXTERM(tt_type_mode) ||
                            ISK95(tt_type_mode)) {
                    /* SCOSC - Save Cursor Position */
                    savecurpos(VTERM,0);
                }
                break;
            case '^': /* (SD) Scroll Down (ECMA 48) */
                if ( pn[1] == 0 )
                    pn[1] = 1 ;
                else if ( pn[1] > VscrnGetHeight(VTERM)
                          -((tt_status)?2:1) - vscrn_c_page_margin_top(VTERM) )
                    pn[1] = VscrnGetHeight(VTERM)
                        -((tt_status)?2:1) - vscrn_c_page_margin_top(VTERM) ;
                if ( debses )
                    break;
                VscrnScroll(VTERM,
                             DOWNWARD,
                             0,
                             VscrnGetHeight(VTERM)
                             -(tt_status[VTERM]?2:1),
                             pn[1],
                             TRUE,
                             SP,
                             FALSE);
                break;
            case 'T':
                /* (SD) Scroll down-scrolls the characters down */
                /* n lines.  The top n lines are    */
                /* cleared to blanks (default: n=1). */
                /* Also (RD) Roll down with SNI 97801 */
                if ( debses )
                    break;

                if ( IS97801(tt_type_mode) ) {
                    /* ignored if outside scroll region */
                    if ( wherey[VTERM] < vscrn_c_page_margin_top(VTERM) ||
                         wherey[VTERM] > vscrn_c_page_margin_bot(VTERM) )
                        break;
                }

                if ( pn[1] == 0 )
                    pn[1] = 1 ;
                else if ( pn[1] > VscrnGetHeight(VTERM)
                          -((tt_status)?2:1) - vscrn_c_page_margin_top(VTERM) )
                    pn[1] = VscrnGetHeight(VTERM)
                        -((tt_status)?2:1) - vscrn_c_page_margin_top(VTERM) ;

                if ( private ) {
                    if ( ISAIXTERM(tt_type_mode) ) {
                        /* Go to column pn[1] of Status Line */
                        setdecssdt(SSDT_HOST_WRITABLE);
                        setdecsasd(SASD_STATUS);
                        lgotoxy(VSTATUS,pn[1],1);
                        break;
                    }
                }
                else if ( ISVT320(tt_type_mode) ||
                          IS97801(tt_type_mode) ) {
                    if ( sni_scroll_mode ) {
                        VscrnScroll(VTERM,
                                     DOWNWARD,
                                     wherex[VTERM]-1,
                                     vscrn_c_page_margin_bot(VTERM)-1,
                                     pn[1],
                                     FALSE,
                                     SP,
                                     FALSE);
                    } else { /* Roll Mode */
                        /* TODO:
                         * This should scroll smoothly. But it shouldn't do so
                         * using VscrnScrollPage. SD (and SU) are for panning
                         * a viewport smaller than the page up and down (like
                         * using the vertical scrollbar), and when smooth
                         * scrolling is on it should pan smoothly.
                         */
                        VscrnScrollPage(
                            VTERM,      /* Vscrn */
                            DOWNWARD,   /* Direction */
                            vscrn_c_page_margin_top(VTERM)-1,   /* Top */
                            vscrn_c_page_margin_bot(VTERM)-1,   /* Bottom */
                            vscrn_c_page_margin_left(VTERM)-1,  /* Left */
                            vscrn_c_page_margin_right(VTERM)-1, /* Right */
                            pn[1],      /* Lines */
                            FALSE,      /* Save */
                            SP,         /* Fill Char */
                            vscrn_current_page_number(VTERM, FALSE) /* page */
                            );
                    }
                }
                /* We don't support paged memory so it does nothing */
                else if (ISHFT(tt_type_mode) || ISANSI(tt_type_mode)) {
                VscrnScroll(VTERM,
                             DOWNWARD,
                             0,
                             VscrnGetHeight(VTERM)
                             -(tt_status[VTERM]?2:1),
                             pn[1],
                             TRUE,
                             SP,
                             FALSE);
                }
                break;
            case 't':   /* Proprietary */
                if ( ISAAA(tt_type_mode) ) {
                    /* zPOP - Pop Line */
                    break;
                }
                else if ( IS97801(tt_type_mode) ) {
                     switch ( pn[1] ) {
                     case 0: /* Disable ID card reader */
                         break;
                     case 1: /* Enable ID Card reader */
                         break;
                     case 2: {
                         /* Query ID Card reader status */
                         /* @ - ID Card Reader Present */
                         /* A = ID Card Reader broken or missing */
                         char buf[8];
                         if ( debses )
                             break;
                         if ( send_c1 )
                             sprintf(buf,"%cPt%c%c",_DCS,'A',_ST8);
                         else
                             sprintf(buf,"%cPPt%c%c\\",ESC,'A',ESC);
                         sendchars(buf,strlen(buf));
                         break;
                     }
                     }
                }
                else if (zdsext) { /* Heath/Zenith/AnnArbor/xterm extension */
                    switch ( pn[1] ) {
                        case 2: {
                            /* xterm - set one or more features of the title
                             * modes (XTSMTITLE) */
                            switch ( pn[2] ) {
                                case 0: /* Set window/icon labels using hexadecimal */
                                    break;
                                case 1: /* Query window/icon labels using hexadecimal */
                                    break;
                                case 2: /* Set window/icon labels using UTF-8. */
                                    break;
                                case 3: /* Query window/icon labels using UTF-8. */
                                    break;
                                default:
                                    break;
                            }
                            break;
                        }
                        default:
                            break;
                    }
                } else {
                    switch ( pn[1] ) {
                    case 24:    /* DECSLPP - Set screen height */
                    case 25:
                    case 36:
                    case 41:
                    case 42:
                    case 48:
                    case 52:
                    case 53:
                    case 72:
                        set_term_height(pn[1]);
                        break;

                        /* These are XTERM functions */
                    case 1: /* Deiconify (Restore window) */
#ifdef KUI
                        gui_win_run_mode(1);
#endif
                        break;
                    case 2: /* Iconify (Minimize window) */
#ifdef KUI
                        gui_win_run_mode(2);
#endif
                        break;
                    case 3: /* Position window (Y=Pn[2],X=Pn[3]) */
#ifdef KUI
                        if ( k < 2 ) {
                            pn[2] = 0;
                            pn[3] = 0;
                        } else if ( k < 3 )
                            pn[3] = 0;

                        gui_position(pn[3],pn[2]);
#endif /* KUI */
                        break;
                    case 4: /* Size window in pixels (Y=Pn[2],X=Pn[3]) */
                        /* 0 means leave that dimension alone */
                        if ( k < 2 ) {
                            pn[2] = 0;
                            pn[3] = 0;
                        } else if ( k < 3 )
                            pn[3] = 0;

                        if ( pn[2] == 0 && pn[3] == 0 )
                            break;
#ifdef KUI
                        gui_resize_pixels(pn[3], pn[2]);
#endif /* KUI */
                        break;
                    case 5: /* Raise Window */
                        /* Not possible to take focus on Windows */
                        break;
                    case 6: /* Lower Window */
                        break;
                    case 7: /* Refresh the xterm window */
#ifdef KUI
                        tt_sync_output_timeout = SYNC_OUTPUT_TIMEOUT;
                        KuiRefreshTerminal();
#endif /* KUI */
                        break;
                    case 8: /* Size window in characters (Y=Pn[2],X=Pn[3]) */
                        /* 0 means leave that dimension alone */
                        if ( k < 2 || pn[2] == 0 && pn[3] == 0 )
                            break;
                        if ( k < 3 )
                            pn[3] = 0 ;
                        if ( pn[2] == 0 )
                            pn[2] = tt_rows[VTERM] ;
                        if ( pn[3] == 0 )
                            pn[3] = tt_cols[VTERM] ;
                        if ( tt_modechg == TVC_ENA ) {
                            tt_szchng[VTERM] = 1 ;
                            tt_rows[VTERM] = pn[2] ;
                            tt_cols[VTERM] = pn[3]%2 ? pn[3]+1 : pn[3] ;
                            VscrnInit( VTERM ) ; /* Size is set here */
                            msleep(50);
                            naws();
                        }
                        break;
                    case 9: {
                        switch (pn[2]) {
                            case 0: /* Restore maximized window. */
                                break;
                            case 1: /* Maximize window (i.e., resize to screen size) */
                                break;
                            case 2: /* Maximize window vertically */
                                break;
                            case 3: /* Maximize window horizontally */
                                break;
                            default:
                                break;
                        }
                        break;
                    }
                    case 10: {
                        switch ( pn[2]) {
                            case 0: /* Undo full-screen mode */
                                break;
                            case 1: /* Change to full-screen */
                                break;
                            case 2: /* Toggle full-screen */
                                break;
                            default:
                                break;
                        }
                    }
                    case 15: { /* Report size of the screen in pixels */
#ifdef KUI
                        int w, h;
                        char buf[30];
                        KuiGetTerminalMaximisedSize(FALSE, &w, &h);

                        if (w < 50000 && h < 50000) { /* Limit response length */
                            sprintf(buf, "[5;%d;%dt", h, w);
                            sendescseq(buf);
                        }
#endif /* KUI */
                        break;
                    }
                    case 16: /* Report xterm character cell size in pixels */
                        break;
                    case 19: { /* Report the size of the screen in characters */
#ifdef KUI
                        int w, h;
                        char buf[30];
                        KuiGetTerminalMaximisedSize(TRUE, &w, &h);

                        if (w < 50000 && h < 50000) { /* Limit response length */
                            sprintf(buf, "[9;%d;%dt", h, w);
                            sendescseq(buf);
                        }
#endif
                        break;
                    }
                    case 20: /* Report Icon Label */
                        break;
                    case 21: /* Report Window Label */
                        break;
                    case 22: { /* xterm: Save icon and window title on stack */
                        switch (pn[2]) {
                            case 0: /* save icon and window. */
                                break;
                            case 1: /* save icon */
                                break;
                            case 2: /* save title */
                                break;
                            default:
                                break;
                        }
                        break;
                    }
                    case 23: /* xterm: Restore title and/or window from stack */
                        switch (pn[2]) {
                            case 0: /* restore icon and window. */
                                break;
                            case 1: /* restore icon */
                                break;
                            case 2: /* restore title */
                                break;
                            default:
                                break;
                        }
                        break;
                    case 18: { /* Report size of Window in chars */
                        char buf[20];
                        int width, height;

                        width = VscrnGetWidth(vmode);
                        height = VscrnGetHeight(vmode);

                        sprintf(buf, "[8;%d;%dt", height, width);
                        sendescseq(buf);

                        break;
                    }
                    case 14: /* Report size of Window in pixels */
                        if (pn[2] == 2) {
                            /* Report xterm window size in pixels */
                        } else {
                            /* Report xterm text area size in pixels */
                        }
                        break;
                    case 13: /* Report position of Window in pixels */
                        if (pn[2] == 2) {
                            /* Report xterm text-area position */
                        } else {
                            /* Report xterm window position */
                        }
                        break;
                    case 11: { /* Report state of Window (normal/iconified) */
#ifdef KUI
                        char buf[20];
                        if (gui_get_win_run_mode() == 2) {
                            sprintf(buf, "[%dt", 2); /* Iconified */
                        } else {
                            sprintf(buf, "[%dt", 1); /* Not iconified */
                        }

                        sendescseq(buf);
#endif
                        break;
                    }
                    }
                }
                break;
            case 'u':
                if ( ISAAA(tt_type_mode) ) {
                    /* zSTP - Set Transfer Point */
                    break;
                }
                else if ( IS97801(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 0: /* 25-line mode on */
                        if ( debses )
                            break;
                        setdecssdt(SSDT_BLANK);
                        vscrn_setc_page_margin_top(VTERM, 1);
                        vscrn_setc_page_margin_bot(VTERM, VscrnGetHeight(VTERM));
                        break;
                    case 1: /* 24-line mode on */
                        if ( debses )
                            break;
                        setdecssdt(SSDT_HOST_WRITABLE);
                        vscrn_setc_page_margin_top(VTERM, 1);
                        vscrn_setc_page_margin_bot(VTERM, VscrnGetHeight(VTERM)-1);
                        break;
                    case 2: /* Clear character NUL */
                        break;
                    case 3: /* Clear character SP */
                        break;
                    case 4: /* Video timeout off */
                        break;
                    case 5: /* Video timeout on */
                        break;
                    case 8: /* Page mode on */
                        if ( debses )
                            break;
                        sni_pagemode = TRUE;
                        break;
                    case 9: /* Auto Roll mode on */
                        if ( debses )
                            break;
                        sni_pagemode = FALSE;
                        break;
                    case 10: /* Roll mode */
                        /* Only affects RD/SD - CSI Pn T */
                        if ( debses )
                            break;
                        sni_scroll_mode = FALSE;
                        break;
                    case 11: /* Scroll mode */
                        /* Only affects RD/SD - CSI Pn T */
                        if ( debses )
                            break;
                        sni_scroll_mode = TRUE;
                        break;
                    case 18: /* Reduced-intensity character display */
                        break;
                    case 19: /* Reduced-intensity background display */
                        break;
                    case 20: /* Dark background (white on black) */
                        if (!decscnm) /* Already normal? */
                            break;
                        else {
                            flipscreen(VTERM);
                            VscrnIsDirty(VTERM);
                        }
                        break;
                    case 21: /* Light background (black on white) */
                        if (decscnm) /* Already reverse */
                            break;
                        else {
                            flipscreen(VTERM);
                            VscrnIsDirty(VTERM) ;
                        }
                        break;
                    }
                }
                else if ( ISANSI(tt_type_mode) ||
                          ISHFT(tt_type_mode) ||
                          ISSCO(tt_type_mode) ||
						  ISLINUX(tt_type_mode) ) {
                    /* Restore Cursor Position */
                    restorecurpos(VTERM,0);
                    break;
                }
                break;
            case 'W':
                if ( ISHFT(tt_type_mode) ||
                     ISLINUX(tt_type_mode) ||
                     ISAAA(tt_type_mode)) {
                    /* CTC - Cursor Tab Stop Control */
                    do {
                        cursordown(0);
                        pn[1] = pn[1] - 1;
                    } while (pn[1] > 0);
                } else if ((ISVT520(tt_type_mode) || ISXTERM(tt_type_mode))
                    && private) {  /* DECST8C - Tab stop every 8 columns */

                    /* This control sequence is documented as being CSI ? 5 W
                     * however the VT520 seems to ignore the parameter entirely.
                     * Any value will result in tabs being set every 8 columns.
                     */

                    int i;
                    int width = VscrnGetWidth(VTERM);

                    /* The VT520 sets tab stops out to 132 columns, so we will
                     * ensure at least that many are set even if the terminal is
                     * currently narrower. */
                    if (width < 132) width = 132;

                    for (i = 1; i < width; i++) {
                        htab[i] = (i % 8) == 1 ? 'T' : '0';
                    }
                }
                break;
            case 'X':
                if (( ISVT220(tt_type_mode) ||
                      ISHFT(tt_type_mode) ||
                      ISLINUX(tt_type_mode) ||
                      ISANSI(tt_type_mode) || 
                      ISAAA(tt_type_mode)) &&
                     private == FALSE &&
                     ansiext == FALSE ) {
                    /* Erase characters (ECH) VT200 */
                    blankvcell.c = ' ' ;
                    blankvcell.video_attr = geterasecolor(VTERM);
                    if ( pn[1] == 0 ) pn[1] = 1 ;
                    if ( pn[1] >
                         VscrnGetWidth(VTERM) + 1
                         - wherex[VTERM] )
                        pn[1] =
                            VscrnGetWidth(VTERM) + 1
                                - wherex[VTERM] ;
                    for ( i = 0 ; i < pn[1] ; i++ ) {
                        VscrnWrtCell(VTERM,
                                      blankvcell,
                                      blankattrib,
                                      wherey[VTERM]-1,
                                      wherex[VTERM]-1+i
                                      );
                    }
                }
                break;
            case 'Y':
                /* Cursor Vertical Tab */
                if ( ISHFT(tt_type_mode) ) {
                }
                break;
            case 'y':   /* Proprietary */
                if ( ISVIP(tt_type_mode) ) {
                    char vipstr[32] ;
                    sprintf(vipstr,"%c[8p  OT%c%c[y7813  P GC  A %c%c",
                             ESC,ETX,ESC,ETX,NUL);
                    sendchars(vipstr,28);
                }
                else if ( ISHFT(tt_type_mode) ) {
                    /* Virtual Terminal locator report */
                    ;
                }
                else if ( IS97801(tt_type_mode) ) {
                    switch ( pn[1] ) {
                    case 1:
                        /* Execute hardware test for terminal */
                        break;
                    case 2:
                        /* Transmit results of hardware test */
                        break;
                    case 3:
                        /* Activate system test and request result */
                        break;
                    case 4:
                        /* Request firmware version of terminal control */
                        break;
                    case 5:
                        /* Transmit firmware version of keyboard */
                        break;
                    case 11:
                        /* Read current key assignment table */
                        break;
                    case 12:
                        /* Query load process for character generator */
                        break;
                    case 19:
                        /* Transmit board code */
                        break;
                    case 20:
                        /* Activate 8-bit mode   */
                        /* US_ASCII to G0   (GL) */
                        /* Brackets to G1        */
                        /* Blanks   to G2        */
                        /* ISO 8859-1 to G3 (GR) */
                        SNI_bitmode(8);
                        sni_chcode_8 = TRUE;
                        break;
                    case 21:
                        /* Activate 7-bit mode */
                        /* US_ASCII to G0  (GL)  */
                        /* US_ASCII to G0  (GR)  */
                        SNI_bitmode(7);
                        sni_chcode_7 = TRUE;
                        break;
                    case 22: {
                        /* Query active mode */
                        char buf[9];
                        sprintf(buf,"%c22y%c%c",
                                 _DCS,
                                 decnrcm?'7':'8',
                                 _ST8);
                        ttol(buf,6);
                        break;
                    }
                    case 30:
                        /* Query load process for string key table */
                        break;
                    }
                }
                else if ( k == 2 && pn[1] == 2 ) { /* Confidence Tests */
                    if ( pn[2] & 0x01 )
                        /* Power-up self test */
                        ;
                    if ( pn[2] & 0x02 )
                        /* Data Loop Back test */
                        ;
                    if ( pn[2] & 0x04 )
                        /* EIA modem control test */
                        ;
                    if ( pn[2] & 0x08 )
                        /* Repeat selected test(s) indefinitely */
                        ;
                    }
                break;
            case 'Z':
                if ( ISANSI(tt_type_mode) &&
                     ansiext ) {
                    resetcolors(1);
                }
                else {
                    /* Cursor Backward Tabulation (CBT) */
                    /* moves active position back n tabstops */
                    if (k < 1 || pn[1] < 1) pn[1] = 1;
                    i = wherex[VTERM];
                    while (pn[1]) {
                        if (i > cursor_left_margin(VTERM)) {
                            do {
                                i--;
                                cursorleft(0);
                            } while ((htab[i] != 'T') && (i >= cursor_left_margin(VTERM) + 1));
                        }
                        pn[1]--;
                    }
                    if (cursor_on_visible_page(VTERM)) {
                        VscrnIsDirty(VTERM);
                    }
                }
                break;
            case 'z':   /* Proprietary */
                if ( ISH19(tt_type) ) {
                    doreset(1) ;
                }
                else if ( ISAAA(tt_type_mode) ) {
                    /* zSTE - Set Transfer End */
                }
                else if ( IS97801( tt_type_mode) ) {
                    /* Define left (pn[1]) and right (pn[2]) margins */
                    /* 1 <= pn[1] < pn[2] <= 80                      */
                    /* This sequence affects only the character that */
                    /* immediately follows this sequence.  That char */
                    /* is used to fill the scroll region using these */
                    /* borders, then the borders revert to 1,80.     */
                    int width = VscrnGetWidth(VTERM);
                    if ( debses )
                        break;
                    if ( pn[1] < 1 || pn[1] > width )
                        pn[1] = 1;
                    if ( pn[2] < 1 || pn[2] > width )
                        pn[2] = width;
                    if ( pn[1] > pn[2] )
                        break;
#ifdef COMMENT
                    /* Not implemented yet. (see above note.) */
                    vscrn_setc_page_margin_left(VTERM, pn[1]);
                    vscrn_setc_page_margin_right(VTERM, pn[2]);
#endif /* COMMENT */
                    break;
                } else if ( ISSCO(tt_type_mode) ) {
                    if ( ansiext ) {
                        /* Clear All Tabs (CAT) */
                        for (j = 1; j <=MAXTERMCOL; ++j)
                            htab[j] = '0';
                    } else {
                        /* Screen Switch - pn[1] specifies screen to switch to */
                    }
                }
                break;
            case ',': {
                achar = (escnext<=esclast)?
                    escbuffer[escnext++]:0;
                switch ( achar ) {
                case 'p':   /* DECLTOD - Load Time of Day */
                    /* pn[1] = hr 00-23; default 8 */
                    /* pn[2] = mn 00-59; default 0 */
                    if ( k < 2 )
                        pn[2] = 0 ;
                    if ( k < 1 )
                        pn[1] = 8 ;
                    loadtod( pn[1], pn[2] ) ;
                    break;
#ifdef KUI
				case 'r':
				case 's':
					/* r - DECDRLBR - Draw Ruled Lines in a pattern
					 * s - DECERLBRP - Erase Ruled Lines in a pattern */
                    if (ISDECTERM(tt_type_mode) || ISK95(tt_type_mode)) {
						int pattern, left, top, width, height;

						if (k < 1) break; /* First parameter (pattern) required */
                        pattern = pn[1];

						/* Starting column */
                        if (k < 2) left = 0;
						else left = pn[2];

                        /* width in columns */
                        if (k < 3) width = 1;
                        else width = pn[3];

                        /* Starting line */
                        if (k < 4) top = 0;
						else top = pn[4];

                        /* height in lines */
                        if (k < 5) height = 1;
                        else height = pn[5];

                        /* DECterm in Tru64 UNIX v5.1B defaults to starting at
                         * the cursor even though the documentation says it
                         * should default to 1,1. Ruled Lines in DECterm have
                         * lots of bugs, so this *could* be another, or perhaps
                         * the documentation is wrong. If the earliest versions
                         * of DECterm supporting Ruled Lines match the behaviour
                         * seen in v5.1B then what the documentation says is
                         * irrelevant. If the behaviour changed at some point
                         * (or is different on OpenVMS), then we might need to
                         * revisit these defaults. */
                        if (left == 0) left = wherex[VTERM];
                        if (top == 0) top = wherey[VTERM];

                        /* with a width and height of 1 */
                        if (width == 0) width = 1;
                        if (height == 0) height = 1;

						ruledlines_escape(pattern, left, top, width, height,
							achar == 'r'); /* 'r' is set, 's' is clear */
					}
					break;
				case 't':
					/* DECERLBRA  - Erase All Ruled Lines in an Area */
					if (ISDECTERM(tt_type_mode) || ISK95(tt_type_mode)) {
						int scope;

						if (k < 1) scope = 1;
						else scope = pn[1];

						if (scope == 0 || scope == 1) {
							/* Erase all ruled lines on screen */

							/* For scope 0/1 DECterm would still require an area
						   	   to be specified, otherwise it would ignore the
						       whole thing. We won't enforce that though.
							if (k < 5) break; */

							decerlbra_escape(1, 1,
								tt_cols[VTERM], tt_rows[VTERM]);

						} else if (scope == 2) {
							/* Erase all ruled lines in an area */

							int left, top, width, height;

							/* Starting column */
                        	if (k < 2) left = 1;
							else left = pn[2];

                        	/* width in columns */
                        	if (k < 3) width = 1;
                    	    else width = pn[3];

            	            /* Starting line */
                	        if (k < 4) top = 1;
							else top = pn[4];

    	                    /* height in lines */
	                        if (k < 5) height = 1;
	                        else height = pn[5];

							decerlbra_escape(left, top, width, height);
						}
					}
					break;
#endif /* KUI */
                case 'x':     /* DECSPMA - Session Page Memory Allocation */
                    if (ISVT520(tt_type_mode)) {
                        /* We don't support multiple sessions, so this just
                         * changes the maximum number of pages available to
                         * applications. Not much validation of set values is
                         * required here, as term_max_page() will do that for
                         * us. */
                        if (k >= 1 && pn[1] > 0) {
                            decspma_max_page = pn[1] - 1; /* Session 1 */
                        }
                    }
                    break;
                case 'z':     /*  DECDLDA */
                    /* Only available for VT520:
                     * "The color terminal does not use this command
                     *  because it has enough memory to give all four
                     *  sessions *Two each.*"
                     *
                     *  Switches between one drcs font buffer per
                     *  session, or two font buffers each for sessions
                     *  one and two. The only valid parameter values
                     *  are 1 and 2 - all other values are ignored. This
                     *  setting is reset to two on hard reset.
                     */
#ifdef KUI
                    if (ISVT520(tt_type_mode) && !ISVT525(tt_type_mode)) {
                        if (k >= 1 && (pn[1] == 1 || pn[1] == 2)) {
                            decdlda = pn[1];
                        }
                    }
#endif /* KUI */
                    break;
                case '}': {    /* DECATC - Alternate Text Color */
                    if (ISVT525(tt_type_mode)) {
                        cell_video_attr_t att = cell_video_attr_init_vio_attribute(0x00);
                        int pmax = current_palette_max_index();

                        if (pn[2] < pmax && pn[3] < pmax) {
                            att = cell_video_attr_set_fg_color(att, color_index_to_vio(pn[2]));
                            att = cell_video_attr_set_bg_color(att, color_index_to_vio(pn[3]));

                            decatc_colors[pn[1]] = att;
                        }
                    }

                    break;
                } /* '}' */
                case '~':      /* DECPS - Play Sound */
                    /* Pvolume ; Pduration ; Pnote */
                    if (ISVT520(tt_type_mode) || ISK95(tt_type_mode)) {
                        UCHAR velocity;
                        int duration, note;
                        int maxnote;
                        if (k < 1) pn[1] = 0;
                        if (pn[1] > 7) return;
                        if (k < 2) pn[2] = 0;
                        if (pn[2] > 255) return;
                        if (k < 3) {
                            k = 3;
                            pn[k] = 0;
                        }

                        /* volume (0-7) to MIDI velocity (0-127) */
                        velocity = pn[1] * 127 / 7;

                        /* duration (0-255) in 1/32nds of a second to
                         * milliseconds. This won't be perfect, but we don't
                         * currently have a microsecond sleep function. So it's
                         * the best we can reasonably do for now.*/
                        duration = pn[2] * 1000 / 32;

                        /* The VT520 only plays the first note. For K95, we'll
                         * play more. */
                        maxnote = ISK95(tt_type_mode) ? k : 3;

                        sound_playing = TRUE;
                        for (note = 3; note <= maxnote; note++) {
                            if (!sound_playing) break;

                            /* A bunch of sites give 72 as the number for C5 in
                             * MIDI, and they progress up from there in the same
                             * order the VT520 manual gives, so... */
                            pn[note] += 71;
                            MakeSound(
                                pn[note] > 96 ? 0 : pn[note],  /* Note out of range? silent */
                                pn[note] == 71 ? 0 : velocity, /* note 0 is silent */
                                duration);
                        }
                        sound_playing = FALSE;
                    };
                    break;
				case '|': {    /*  DECAC - Assign Color */
					if (ISVT525(tt_type_mode)) {
						cell_video_attr_t att = cell_video_attr_init_vio_attribute(0x00);
                    	int pmax = current_palette_max_index();

						if (pn[2] < pmax && pn[3] < pmax) {
                            att = cell_video_attr_set_fg_color(att, color_index_to_vio(pn[2]));
                            att = cell_video_attr_set_bg_color(att, color_index_to_vio(pn[3]));

                            if (pn[1] == 1) {
								/* Normal text */
								defaultattribute = att;
							} else if (pn[1] == 2) {
								/* Window frame.
							     TODO: I'm not sure what exactly this does on the
								     VT525, but in the Windows Terminal it sets
								     the tab color. We don't have tabs, but we
                                     could set the border color (not used on Windows
									 currently), or the status line color.
								 */
							}
                        }
					}
					break;
				} /* '|' */
                } /* switch (achar) */
                break;
            }
            case '\'':
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch (achar) {
                case '~':
                    if ( ISVT420(tt_type_mode) ) {
                        /* DECDC - Delete Column */


                        /* "DECDC is ignored if the active position is outside
                         * the Scroll Area" - STD 070 */
                        if (wherex[VTERM] >= vscrn_c_page_margin_left(VTERM) &&
                            wherex[VTERM] <= vscrn_c_page_margin_right(VTERM) &&
                            wherey[VTERM] >= vscrn_c_page_margin_top(VTERM) &&
                            wherey[VTERM] <= vscrn_c_page_margin_bot(VTERM))
                        {
                            viocell cell ;
                            int top_row, bot_row, left_col, right_col;
                            cell.c = SP ;
                            cell.video_attr = geterasecolor(VTERM) ;
                            if ( k < 1 || pn[1] == 0 )
                                pn[1] = 1;
                            else if ( pn[1] > VscrnGetWidth(VTERM)-1 )
                                pn[1] = VscrnGetWidth(VTERM)-1 ;


                            top_row = vscrn_c_page_margin_top(VTERM) - 1;
                            bot_row = vscrn_c_page_margin_bot(VTERM) - 1;
                            left_col = wherex[VTERM] - 1;
                            right_col = vscrn_c_page_margin_right(VTERM) - 1;

                            VscrnScrollLf( VTERM,
                                           top_row, /* top row */
                                           left_col, /* left col */
                                           bot_row, /* bot row */
                                           right_col,  /* right col */
                                           pn[1],
                                           cell);
                        }
                    }
                    break;
                case '}':
                    if ( ISVT420(tt_type_mode) ) {
                        /* DECIC - Insert Column */

                        /* "DECIC is ignored if the active position is outside
                         * the Scroll Area" - STD 070 */
                        if (wherex[VTERM] >= vscrn_c_page_margin_left(VTERM) &&
                            wherex[VTERM] <= vscrn_c_page_margin_right(VTERM) &&
                            wherey[VTERM] >= vscrn_c_page_margin_top(VTERM) &&
                            wherey[VTERM] <= vscrn_c_page_margin_bot(VTERM))
                        {
                            viocell cell ;
                            int top_row, bot_row, left_col, right_col;
                            cell.c = SP ;
                            cell.video_attr = geterasecolor(VTERM) ;

                            if ( k < 1 || pn[1] == 0 )
                                pn[1] = 1;
                            else if ( pn[1] > VscrnGetWidth(VTERM)-1 )
                                pn[1] = VscrnGetWidth(VTERM)-1 ;

                            top_row = vscrn_c_page_margin_top(VTERM) - 1;
                            bot_row = vscrn_c_page_margin_bot(VTERM) - 1;
                            left_col = wherex[VTERM] - 1;
                            right_col = vscrn_c_page_margin_right(VTERM) - 1;

                            /* This checks LeftCol>rightCol && rightcol < width
                             *              && botrow < height */
                            VscrnScrollRt( VTERM,  /* vmode */
                                           top_row,     /* top row */
                                           left_col,    /* left col */
                                           bot_row,     /* bot row */
                                           right_col,   /* right col */
                                           pn[1],       /* columns */
                                           cell);       /* cell to insert */
                        }
                    }
                    break;
                }
                break;
            case SP:
            if ( ISSCO(tt_type_mode) ) {
                /* SCO ANSI violates the rules and uses SP as a final character */
                do {
                    cursorleft(0);
                    pn[1] -= 1;
                } while (pn[1] > 0);
                break;
            } else {
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch (achar) {
                case '@': {
                    /* Scroll Left - Pan Right */
                    viocell cell ;
                    cell.c = SP ;
                    cell.video_attr = geterasecolor(VTERM) ;
                    if ( pn[1] == 0 )
                        pn[1] = 1 ;
                    else if ( pn[1] > VscrnGetWidth(VTERM)-1 )
                        pn[1] = VscrnGetWidth(VTERM)-1 ;
                    VscrnScrollLf( VTERM,
                                   0,
                                   0,
                                   VscrnGetHeight(VTERM)
                                   -(tt_status[VTERM]?2:1),
                                   VscrnGetWidth(VTERM)-1,
                                   pn[1],
                                   cell);
                    break;
                }
                case 'A': {
                    /* Scroll Right - Pan Left */
                    viocell cell ;
                    cell.c = SP ;
                    cell.video_attr = geterasecolor(VTERM) ;
                    if ( pn[1] == 0 )
                        pn[1] = 1 ;
                    else if ( pn[1] > VscrnGetWidth(VTERM)-1 )
                        pn[1] = VscrnGetWidth(VTERM)-1 ;
                        VscrnScrollRt( VTERM,
                                       0,
                                       0,
                                       VscrnGetHeight(VTERM)
                                       -(tt_status[VTERM]?2:1),
                                       VscrnGetWidth(VTERM)-1,
                                       pn[1],
                                       cell);
                        break;
                }
				case 'P':	/* PPA - Page Position Absolute */
					if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
						int page = pn[1] - 1;

						/* Don't allow switching to the alternate buffer page */
						if (ISK95(tt_type_mode)) {
							if (page == ALTERNATE_BUFFER_PAGE(VTERM)) {
								page = vscrn[vmode].cursor.p;
							}
						}

						if (!on_alternate_buffer(VTERM)) {
							switch_to_page(
								VTERM,
								page,
								vscrn[VTERM].page_cursor_coupling);
						}
					}
					break;
				case 'Q':	/* PPR - Page Position Relative */
					if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
						if (!on_alternate_buffer(VTERM)) {
							next_page(VTERM, pn[1]);
						}
					}
					break;
				case 'R':	/* PPB - Page Position Backward */
					if (ISVT330(tt_type_mode) || ISVT420(tt_type_mode)) {
						if (!on_alternate_buffer(VTERM)) {
							previous_page(VTERM, pn[1]);
						}
					}
					break;
                case 'p':       /* DECSSCLS  - Set Scroll Speed - VT510 */
#ifdef KUI
                    if (ISK95(tt_type_mode)) {
                        switch (pn[1]) {
                        case 0: smooth_speed_pending = 3; break;
                        case 1: smooth_speed_pending = 6; break;
                        case 2: smooth_speed_pending = 9; break;
                        case 3: smooth_speed_pending = 12; break;
                        case 4: smooth_speed_pending = 18; break;
                        case 5: smooth_speed_pending = 22; break;
                        case 6: smooth_speed_pending = 27; break;
                        case 7: smooth_speed_pending = 31; break;
                        case 8: smooth_speed_pending = 36; break;
                        }
                        if (pn[1] == 9) JumpScroll();
                        else if (pn[1] < 9) SmoothScroll();
                    }
                    else
#endif /* KUI */
                    if (ISVT520(tt_type_mode)) {
                        if (pn[1] <= 3) SmoothScroll();
                        else if (pn[1] <= 8) {
#ifdef KUI
                            smooth_speed_pending = 18;
#endif /* KUI */
                            SmoothScroll();
                        } else if (pn[1] == 9) {
                            JumpScroll();
                        }
                    }
                    break;
                case 'q':       /* DECSCUSR - Set Cursor Type - VT520 */
                    switch ( pn[1] ) {
                    case 0:
                    case 1:
                        /* Blinking Block */
                        tt_cursor = TTC_BLOCK ;
						tt_cursor_blink = 1 ;
                        break;
                    case 2:
                        /*  Steady Block */
                        tt_cursor = TTC_BLOCK ;
						tt_cursor_blink = 0 ;
                        break;
                    case 3:
                        /* Blinking Underline */
                        tt_cursor = TTC_ULINE ;
						tt_cursor_blink = 1 ;
                        break;
                    case 4:
                        /* Steady Underline */
                        tt_cursor = TTC_ULINE ;
						tt_cursor_blink = 0 ;
                        break;
                    }
                    setcursormode() ;
                    cursorena[VTERM] = TRUE;
                    break;
                case 't':   /* DECSWBV - Set Warning Bell Volume */
#ifdef NT
                    if (ISVT520(tt_type_mode) || ISK95(tt_type_mode) || ISXTERM(tt_type_mode)) {
                        extern int beepvolume;
                        if (k < 1) pn[1] = 5;
                        switch ( pn[1] ) {
                            case 1:
                                /* off */
                                tt_bell = XYB_NONE;
                                break;
                            case 2:
                            case 3:
                            case 4:
                                /* low */
                                tt_bell = XYB_AUD | XYB_MIDI;
                                beepvolume = BEEP_VOLUME_LOW;
                                break;
                            case 5:
                            case 6:
                            case 7:
                            case 8:
                                /* high */
                                tt_bell = XYB_AUD | XYB_MIDI;
                                beepvolume = BEEP_VOLUME_HIGH;
                                break;
                        }
                    }
#endif /* NT */
                    break;
                }
                break;
            } /* SP */
            case '~': {
                if ( kermext ) {
                    /* MS-DOS Kermit PRODUCT macro */
#ifdef CK_APC
                    sprintf(apcbuf,
                             "do product %d %d %d %d %d %d %d %d %d",
                             1<=k?pn[1]:0,
                             2<=k?pn[2]:0,
                             3<=k?pn[3]:0,
                             4<=k?pn[4]:0,
                             5<=k?pn[5]:0,
                             6<=k?pn[6]:0,
                             7<=k?pn[7]:0,
                             8<=k?pn[8]:0,
                             9<=k?pn[9]:0);
                    apc_command(APC_LOCAL,apcbuf);
#endif /* CK_APC */
                }
                else { /* DECTME */
                    switch ( pn[1] ) {
                    case 0:
                    case 1:
                        switch ( tt_type ) {
                        case TT_VT220:
                        case TT_VT220PC:
                        case TT_VT320:
                        case TT_VT320PC:
                        case TT_WY370:
                            tt_type_mode = tt_type;
                            break;
                        default:
                            tt_type_mode = TT_VT320 ;
                            break;
                        }
                        if ( k > 1 && pn[2] == 1 )
                            send_c1 = FALSE ; /* 7-bit cntrols */
                        else
                            send_c1 = TRUE ; /* 8-bit controls */
                        break;
                    case 2:
                        switch ( tt_type ) {
                        case TT_VT100:
                            tt_type_mode = TT_VT100 ;
                            break;
                        default:
                            tt_type_mode = TT_VT102 ;
                            break;
                        }
                        break;
                    case 3:
                        tt_type_mode = TT_VT52;
                        break;
                    case 4:   /* PC TERM */
                        break;
                    case 5:
                        tt_type_mode = TT_WY60 ;
                        break;
                    case 6:   /* WYSE PC TERM */
                        break;
                    case 7:
                        tt_type_mode = TT_WY50 ;
                        break;
                    case 8:   /* WYSE 150/120 */
                        break;
                    case 9:
                        tt_type_mode = TT_TVI950 ;
                        break;
                    case 10:
                        tt_type_mode = TT_TVI925 ;
                            break;
                    case 11:
                        tt_type_mode = TT_TVI910 ;
                        break;
                    case 12:  /* ADDS A2 */
                        break;
                    case 13:
                        tt_type_mode = TT_SCOANSI ;
                        break;
                    case 14:  /* WYSE 325 */
                    break;
                    }
                    /* status line needs to be updated */
                    VscrnIsDirty(VTERM);
                }
                break;
            }
            case '[': {
                if ( ISHFT(tt_type_mode) ) {
                    /* Select Reversed String */
                    switch ( pn[1] ) {
                    case 0: /* End Push */
                        break;
                    case 1: /* Start Push */
                        break;
                    }
                }
                break;
            }
            case ']': {
                if ( ISHFT(tt_type_mode) ) {
                    /* Select Alternate Presentation Variant */
                    for (j = 1; j <= k; ++j) { /* Go thru all Pn's */
                        switch ((pn[j])) {   /* This one... */
                        case 0:
                            /* Set Default Values for BIDI */
                            break;
                        case 1:
                            /* Set Arabic numeric shapes */
                            break;
                        case 2:
                            /* Set Hindi numeric shapes */
                            break;
                        case 3:
                            /* Set symmetric swapping mode */
                            /* for directional characters */
                            break;
                        case 5:
                            /* the following graphic character */
                            /* is presented in its isolated form */
                            /* (Arabic only) */
                            /* effects only the following char */
                            /* unless used with 21 and 22 */
                            break;
                        case 6:
                            /* the following graphic character */
                            /* is presented in it initial form */
                            /* (Arabic only) */
                            /* effects only the following char */
                            /* unless used with 21 and 22 */
                            break;
                        case 7:
                            /* the following graphic character */
                            /* is presented in it middle form */
                            /* (Arabic only) */
                            /* effects only the following char */
                            /* unless used with 21 and 22 */
                        case 8:
                            /* the following graphic character */
                            /* is presented in it final form */
                            /* (Arabic only) */
                            /* effects only the following char */
                            /* unless used with 21 and 22 */
                            break;
                        case 13:
                            /* set Special shaping mode */
                            break;
                        case 14:
                            /* set standard shaping mode */
                            break;
                        case 15:
                            /* set symmetric mode */
                            break;
                        case 18:
                            /* Passthru (everything) */
                            break;
                        case 19:
                            /* Passthru (everything but numbers) */
                            break;
                        case 20:
                            /* Contextual numbers (device dependent) */
                            break;
                        case 21:
                            /* lock 5,6,7,8 */
                            break;
                        case 22:
                            /* unlock */
                            break;
                        case 23:
                            /* set the nonull mode */
                            break;
                        case 24:
                            /* reset the nonull mode */
                            break;
                        default:
                            break;
                        }
                    }
                } else if ( ISLINUX(tt_type_mode) ) {
					switch(pn[1]) {
					case 1:  /* Set color n as the underline color */
						/* underline color in pn[2] */
						underlineattribute = cell_video_attr_set_fg_color(
							underlineattribute, pn[2]);
						break;
					case 2:	 /* Set color n as the dim color */
						/* dim color in pn[2] */
						dimattribute = cell_video_attr_set_fg_color(
							dimattribute, pn[2]);
						break;
					case 8:  /* Make the current color pair the default attributes. */
						defaultattribute = attribute;
						break;
					}

                    /*
                    ESC [ 1 ; n ]       Set color n as the underline color
                    ESC [ 2 ; n ]       Set color n as the dim color
                    ESC [ 8 ]           Make the current color pair the default attributes.
                    ESC [ 9 ; n ]       Set screen blank timeout to n minutes.
                    ESC [ 10 ; n ]      Set bell frequency in Hz.
                    ESC [ 11 ; n ]      Set bell duration in msec.
                    ESC [ 12 ; n ]      Bring specified console to the front.
                    ESC [ 13 ]          Unblank the screen.
                    ESC [ 14 ; n ]      Set the VESA powerdown interval in minutes.
                    */
                }
                break;
            }
            case '&': {
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch (achar) {
                case 'x': /* Enable Session */
                    break;
                }
                break;
            }
            default:
                debug(F111,"ANSI X3.64","unknown achar",achar);
                break;
            }       /* third level of left bracket */
        }   /* Esc [ Pn...Pn x   functions */
            break;
        }   /* Second level */

    } /* Left square bracket */
}

void
vtescape( void )
{
    unsigned short  k;
    viocell         blankvcell ;
    int             i;

    /* Initialize default values */
    for (i=0;i<PN_MAX;i++) {
        pn[i]=0;
        pn_pe_start[i]=-1;
        pn_pe_count[i]=0;
    }
    for (i=0;i<PE_MAX;i++)
        pe[i]=0;
    private = ansiext = zdsext = kermext = FALSE;

    escstate = ES_NORMAL;               /* Set escape state back to normal */
    escnext = 1;                        /* Point to beginning of esc seq buf */
    if (debses)                         /* If TERMINAL DEBUG ON, */
      return;                           /* we don't actually do anything. */

    achar = (escnext<=esclast)?escbuffer[escnext++]:0;
    if ( !xprint /* && screenon */) {
        /* screen escape sequences  */
        switch (achar) {                /* First Level */
        case '[':      /* CSI */
            vtcsi();
            break;
        case SP:
              achar = (escnext<=esclast)?escbuffer[escnext++]:0;
              if (ISVT220(tt_type_mode)) {
                  switch (achar) {
                  case 'F':  /* S7C1T */
                      send_c1 = FALSE;
                      break;
                  case 'G':  /* S8C1T */
                      send_c1 = TRUE ;
                      break;
                  case '0':     /* WYID */
                      if ( tt_type == TT_WY370 )
                          sendchars("370\r",4);
                      break;
                  case 'L': /* Select ANSI Level 1 */
                      /* ASCII set designated as G0 */
                      /* ISO Latin-1 supplemental set designated as G1 */
                      /* G0 mapped into GL */
                      /* G1 mapped into GR */
                  case 'M': /* Select ANSI Level 2 */
                      /* ASCII set designated as G0 */
                      /* ISO Latin-1 supplemental set designated as G1 */
                      /* G0 mapped into GL */
                      /* G1 mapped into GR */
                  case 'N': /* Select ANSI Level 3 */
                      /* ASCII set designated as G0 */
                      /* G0 mapped into GL */
                      {
                          decnrcm = FALSE ;
                          /* we treat all of the conformance levels the same    */
                          /* ISO-4873 does not specify that lower levels cannot */
                          /* support the capabilities of the higher levels      */
                          for ( i = 0 ; i < 4 ; i++ ) {
                              G[i].designation = G[i].def_designation ;
                              G[i].size = G[i].def_size ;
                              G[i].c1   = G[i].def_c1 ;
                              G[i].national = CSisNRC(G[i].designation);
                              if ( G[i].def_designation == FC_TRANSP ) {
                                  G[i].rtoi = NULL ;
                                  G[i].itol = NULL ;
                                  G[i].itor = NULL ;
                                  G[i].ltoi = NULL;
                              }
                              else {
                                  G[i].rtoi = xl_u[G[i].def_designation];
                                  if ( ck_isunicode() ) {
                                      G[i].itol = NULL ;
                                      G[i].ltoi = NULL;
                                  }
                                  else {
                                      G[i].itol = xl_tx[tcsl] ;
                                      G[i].ltoi = xl_u[tcsl] ;
                                  }
                                  G[i].itor = xl_tx[G[i].def_designation];
                              }
                          }
                      }
                      break;
                  case '}':     /* DECKBD */
                      /* Pn[1] specifies the keyboard Layout */
                      /*       0,1, or None - VT             */
                      /*       2            - enhanced PC    */
                      /* Pn[2] indicates the national keyboard language */
                      /*       0,1, or None - North American */
                      /*       2            - British */
                      /*       3            - Belgian (Flemish) */
                      /*       4            - French Canadian */
                      /*       5            - Danish */
                      /*       6            - Finnish */
                      /*       7            - German */
                      /*       8            - Dutch */
                      /*       9            - Italian */
                      /*       10           - Swiss French */
                      /*       11           - Swiss German */
                      /*       12           - Swedish */
                      /*       13           - Norwegian */
                      /*       14           - French */
                      /*       15           - Spanish */
                      /*       16           - Portuguese */
                      /*       19           - Hebrew */
                      /*       22           - Greek */
                      /*       28           - Canadian (English) */
                      /*       29           - Turkish Q/Turkish */
                      /*       30           - Turkish F */
                      /*       31           - Hungarian */
                      /*       33           - Slovak */
                      /*       34           - Czech */
                      /*       35           - Polish */
                      /*       36           - Romanian */
                      /*       38           - SCS */
                      /*       39           - Russian */
                      /*       40           - Latin American */
                      break;
                      if ( k<1 )
                          pn[1] = 1;
                      if ( k<2 )
                          pn[2] = 0;

                      /* We do not support the PC mode yet */
                      if ( pn[1] != 0 && pn[1] != 1 )
                          break;

                      switch ( pn[2] ) {
                      case VTL_NORTH_AM:  /* North American */
                          /* Multinational: Latin-1   */
                          /* National:      US_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_ASCII;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_BRITISH :
                          /* Multinational: Latin-1   */
                          /* National:      UK_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_BRITISH;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_FRENCH  :
                      case VTL_BELGIAN :
                      case VTL_CANADIAN:
                          /* Multinational: Latin-1   */
                          /* National:      FR_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_FRENCH;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_FR_CAN  :
                          /* Multinational: Latin-1   */
                          /* National:      FC_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_CN_FRENCH;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_DANISH  :
                      case VTL_NORWEGIA:
                          /* Multinational: Latin-1   */
                          /* National:      NO_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_NORWEGIAN;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_FINNISH :
                          /* Multinational: Latin-1   */
                          /* National:      FI_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_FINNISH;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_GERMAN  :
                          /* Multinational: Latin-1   */
                          /* National:      GR_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_GERMAN;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_DUTCH   :
                          /* Multinational: Latin-1   */
                          /* National:      DU_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_DUTCH;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_ITALIAN :
                          /* Multinational: Latin-1   */
                          /* National:      IT_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_ITALIAN;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_SW_FR   :
                      case VTL_SW_GR   :
                          /* Multinational: Latin-1   */
                          /* National:      CH_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_SWISS;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_SWEDISH :
                          /* Multinational: Latin-1   */
                          /* National:      SW_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_SWEDISH;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_SPANISH :
                          /* Multinational: Latin-1   */
                          /* National:      SP_ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_SPANISH;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_PORTUGES:
                          /* Multinational: Latin-1   */
                          /* National:      Portugese ASCII  */
                          dec_lang = pn[2];
                          dec_nrc = TX_PORTUGUESE;
                          dec_kbd = TX_8859_1;
                          break;
                      case VTL_HEBREW  :
                          /* Multinational: Latin-Hebrew / DEC-Hebrew  */
                          /* National:      DEC 7-bit Hebrew  */
                          dec_lang = pn[2];
                          dec_nrc = TX_HE7;
                          dec_kbd = TX_8859_8;
                          break;
                      case VTL_GREEK   :
                          /* Multinational: Latin-Greek / DEC-Greek   */
                          /* National:      DEC Greek NRC             */
                          /* is ELOT927 equivalent to DEC Greek????   */
                          dec_lang = pn[2];
                          dec_nrc = TX_ELOT927;
                          dec_kbd = TX_8859_7;
                          break;
#ifdef COMMENT
                      case VTL_TURK_Q  :
                      case VTL_TURK_F  :
                          /* Multinational: Latin-Turkish / DEC-Turkish   */
                          /* National:      DEC 7-bit Turkish             */
                          break;
#endif /* COMMENT */
                      case VTL_HUNGARIA:
                          /* Multinational: Latin-2   */
                          /* National:      no national mode  */
                          dec_lang = pn[2];
                          dec_nrc = TX_HUNGARIAN;
                          dec_kbd = TX_8859_2;
                          break;
                      case VTL_SLOVAK  :
                      case VTL_CZECH   :
                      case VTL_POLISH  :
                      case VTL_ROMANIAN:
                          /* Multinational: Latin-2   */
                          /* National:      no national mode  */
                          dec_lang = pn[2];
                          dec_nrc = TX_ASCII;
                          dec_kbd = TX_8859_2;
                          break;
                      case VTL_RUSSIAN :
                          /* Multinational: Latin-Cyrillic / KOI-8   */
                          /* National:      DEC Russian NRC  */
                          dec_lang = pn[2];
                          dec_nrc = TX_KOI7;
                          dec_kbd = TX_8859_5;
                          break;
                      case VTL_LATIN_AM:
                          /* Multinational: not listed in table   */
                          /* National:      not listed in table  */
                          dec_lang = pn[2];
                          dec_nrc = TX_ASCII;
                          dec_kbd = TX_8859_1;
                          break;
#ifdef COMMENT
                      case VTL_SCS     :
                          /* Multinational: Latin-2   */
                          /* National:      SCS NRC   */
                          break;
#endif /* COMMENT */
                      }
                  }
              }
              break;
        case '\\':
              if ( ISH19(tt_type_mode) ) {
                  /* Exit Hold Screen Mode */
              }
              /* String Terminator */
              /*
                 Only here for debugging purposes; really handled in cwrite()
                 Assuming we are in a string; otherwise, we ignore it.
                 */
              break;
        case '@':
            if ( ISH19(tt_type_mode) ) {
                /* Enter Insert Character Mode */
                insertmode = TRUE ;
            }
            break;
        case '1':
                if ( ISH19(tt_type_mode) ) {
                    /* Enter Keypad Shift Mode */
                    tt_shift_keypad = TRUE ;
                    break;
                }
                else if ( ISVT100(tt_type_mode) ) {
                    /* Graphic Processor On */
                }
                break;
        case '2':
              if ( ISVT100(tt_type_mode) ) {
                    /* Graphic Processor Off */
              }
              break;
        case 5:
            /* Wy75 - Transmit Character at Cursor */
            if ( ISAAA(tt_type_mode) ) {
                /* AnnArbor: zTFC - Toggle Fast-Blink Cursor */
            }
            break;
        case '6':  
            if ( ISAAA(tt_type_mode) ) {
                /* AnnArbor: zTI - Toggle IRM */
            } else if (ISVT100(tt_type_mode)) { /* TODO: Should be ISVT420 */
                /* DECBI - Back Index */
				if ( wherex[VTERM] == vscrn_c_page_margin_left(VTERM) &&
						wherey[VTERM] >= vscrn_c_page_margin_top(VTERM) &&
						wherey[VTERM] <= vscrn_c_page_margin_bot(VTERM) ) {
					int leftcol = vscrn_c_page_margin_left(VTERM) - 1;
					int rightcol = vscrn_c_page_margin_right(VTERM) - 1;
                    blankvcell.c = SP;
                    blankvcell.video_attr = geterasecolor(VTERM);
                    VscrnScrollRt(VTERM,				 /* VMODE */
                               vscrn_c_page_margin_top(VTERM) - 1,  /* TopRow */
                               leftcol,			    	 /* LeftCol */
                               vscrn_c_page_margin_bot(VTERM) - 1,  /* BotRow */
                               rightcol,                 /* RightCol */
                               1, blankvcell);			 /* Columns, Cell */
                } else if (wherex[VTERM] > 1) {
					cursorleft(0);
				}
            }
            break;
        case '7':
            /* AnnArbor - zSC - Save Cursor */
            /* Save cursor position and attributes */
            if ( ISANSI(tt_type_mode) || ISAAA(tt_type_mode) )
                savecurpos(VTERM,0);
            else
                savecurpos(VTERM,1);
            break;
        case '8':
            /* AnnArbor: - zRC - Restore Cursor */
            /* Restore Cursor Position and attributes */
            if ( ISANSI(tt_type_mode) || ISAAA(tt_type_mode) )
                restorecurpos(VTERM,0);
            else
                restorecurpos(VTERM, 1);
            break;
        case '9':  
            if ( ISAAA(tt_type_mode) ) {
                /* zCGR - Change Graphic Rendition to Qualified Area */
		  		/* Default area goes from Current Cursor position to End of Screen */
		  		/* Lawrence A Deck - Raytheon 1 Nov 2002 */

		  		int start_x, start_y, end_x, end_y, x, y;
		  		int h = VscrnGetHeight(VTERM)-(tt_status[vmode]?1:0);
		  		int w = VscrnGetWidth(VTERM);
		      
		  		start_x = wherex[VTERM];
		  		start_y = wherey[VTERM];
		  		end_x = w;
		  		end_y = h;

		  		for ( x=start_x;
					x < (start_y == end_y ? end_x : MAXTERMCOL);
					x++ ) {
		      		viocell * pcell = VscrnGetCell(VTERM,x-1,start_y-1, FALSE);
		      		pcell->video_attr = attribute;
		      		VscrnWrtCell( VTERM, *pcell, attrib, start_y - 1, x - 1);
		  		}
		  		if ( start_y != end_y ) {
		      		for ( y=start_y+1; y<end_y; y++) {
			  			for ( x=0; x<MAXTERMCOL; x++ ) {
			    	  		viocell * pcell = VscrnGetCell(VTERM,x-1,y-1, FALSE);
				      		pcell->video_attr = attribute;
				      		VscrnWrtCell( VTERM, *pcell, attrib, y - 1, x - 1);
			  			}
		      		}
		      		for ( x=0;
			    		x <= end_x;
			    		x++ ) {
			  		viocell * pcell = VscrnGetCell(VTERM,x-1,end_y-1, FALSE);
			  		pcell->video_attr = attribute;
			  		VscrnWrtCell( VTERM, *pcell, attrib,
						end_y - 1,
						x - 1);
		      		}
				}
            } else if (ISVT100(tt_type_mode)) {  /* TODO: Should be ISVT420 */
                /* DECFI - Forward Index */
				if (wherex[VTERM] == vscrn_c_page_margin_right(VTERM) &&
				       wherey[VTERM] >= vscrn_c_page_margin_top(VTERM) &&
				       wherey[VTERM] <= vscrn_c_page_margin_bot(VTERM) ) {
					int leftcol = vscrn_c_page_margin_left(VTERM) - 1;
					int rightcol = vscrn_c_page_margin_right(VTERM) - 1;
					blankvcell.c = SP;
					blankvcell.video_attr = geterasecolor(VTERM);
					VscrnScrollLf(VTERM,						   /* VMODE */
                               vscrn_c_page_margin_top(VTERM) - 1, /* TopRow */
                               leftcol,							   /* LeftCol */
                               vscrn_c_page_margin_bot(VTERM) - 1, /* BotRow */
                               rightcol,		                  /* RightCol */
                               1, blankvcell);				/* Columns, Cell */
				} else if (wherex[VTERM] < VscrnGetWidth(VTERM)) {
					cursorright(0);
				}
              }
	          if (cursor_on_visible_page(VTERM)) {
                  VscrnIsDirty(VTERM);
              }
            break;
        case ':':
            if ( ISAAA(tt_type_mode) ) {
                /* zGUA - Guard Unprotected Areas */
            }
            break;
        case '`':
            if ( ISVIP(tt_type_mode) ) {
                /* Honeywell Clear screen, cursor does not move */
                clrscreen(VTERM,SP);
            }
            else if ( IS97801(tt_type_mode) ||
                      ISHFT(tt_type_mode) || 
                      ISAAA(tt_type_mode) ) {
                /* DMI (Disable Manual Input */
                keylock = TRUE ;
                break;
            }
            break;
        case 'A':
            if ( ISVT52(tt_type_mode) ) /* VT52 control */
                cursorup(0);
            break;
        case 'a':
            if ( ISAAA(tt_type_mode) ) {
                /* INT - INTERRUPT */
            }
            break;
        case 'B':
            if ( ISVT52(tt_type_mode) ) /* VT52 control */
                cursordown(0);
            break;
        case 'b':
            if ( ISH19(tt_type_mode) ) {
                /* Erase Beginning of Display */
                clrboscr_escape(VTERM,SP);
            }
            else if ( IS97801(tt_type_mode) ||
                      ISHFT(tt_type_mode) ||
                      ISAAA(tt_type_mode)) {
                /* EMI (Enable Manual Input) */
                keylock = FALSE ;
                break;
            }
            break;
        case 'C':
            if ( ISVT52(tt_type_mode) ) /* VT52 control */
                cursorright(0);
            break;
        case 'c':
            /* Reset - RIS */
            doreset(1);
            break;
        case 'D':
            if ( ISVT52(tt_type_mode) ) /* VT52 control */
                cursorleft(0);
            else if ( ISVT100(tt_type_mode) ) {/* IND - Index */
                if (wherey[VTERM] == vscrn_c_page_margin_bot(VTERM)) {
                    VscrnScrollPage(VTERM,
                                 UPWARD,
                                 vscrn_c_page_margin_top(VTERM) - 1,
                                 vscrn_c_page_margin_bot(VTERM) - 1,
                                 vscrn_c_page_margin_left(VTERM) - 1,
                                 vscrn_c_page_margin_right(VTERM) - 1,
                                 1,
                                 (vscrn_c_page_margin_top(VTERM)==1),
                                 SP,
                                 vscrn_current_page_number(vmode, FALSE));
                } else
                    cursordown(0);
            }
            break;
        case 'E':
            if ( ISH19(tt_type_mode) ) {
                /* Clear Display (Shift Erase) */
                clrscreen(VTERM,SP);
                lgotoxy(VTERM,1,1);       /* and home the cursor */
            }
            else {                      /* NEL - Next Line */
                cursornextline(TRUE, 1);
            }
            break;
        case 'F':
            if ( ISVT52(tt_type_mode) ) /* VT52 control */
                vt52graphics = TRUE;
            else if ( ISVT220(tt_type_mode) ) {
                /* SSA - Start Selected Area */
                ;
            }
            break;
        case 'G':
            if ( ISVT52(tt_type_mode) ) /* VT52 control */
                vt52graphics = FALSE;
            else if ( ISVT220(tt_type_mode) ) {
                /* ESA - End selected area */
                ;
            }
            break;
        case 'H':
              if ( ISVT100(tt_type_mode) ) {
                  /* HTS - Set Tab Stop */
                  htab[wherex[VTERM]] = 'T';
              }
              else if ( ISVT52(tt_type_mode) )
                  /* Cursor Home */
                  lgotoxy(VTERM,1, 1);
              break;
        case 'I':                       
            if ( ISAAA(tt_type_mode) ) {
                /* HTJ - Horizontal Tab with Justify */
                ;
            } else if (ISVT52(tt_type_mode)) {
                /* Reverse Linefeed */
                if (vscrn_c_page_margin_top(VTERM) == wherey[VTERM])
                    VscrnScroll(VTERM,
                                 DOWNWARD,
                                 vscrn_c_page_margin_top(VTERM) - 1,
                                 vscrn_c_page_margin_bot(VTERM) - 1,
                                 1,
                                  FALSE,
                                  SP,
                                 FALSE );
                else
                    cursorup(0);
            }
            break;
        case 'J':
            if (ISVT52(tt_type_mode))
                /* VT52 control */
                clreoscr_escape(VTERM,SP);
            break;
        case 'j':
            if ( ISH19(tt_type_mode) ) {
                /* H19 - Save Cursor Position */
                savecurpos(VTERM,0);
            }
            break;
        case 'K':
            if (ISVT52(tt_type_mode))
                /* VT52 control */
                clrtoeoln(VTERM,SP);
            break;
        case 'k':
            if (ISH19(tt_type_mode)) {
                /* H19 - Restore Cursor Position */
                restorecurpos(VTERM,0);
            }
            break;
        case 'L':
            if ( ISH19(tt_type_mode) ) {
                /* H19 - Insert Line */
                VscrnScroll(VTERM,
                             DOWNWARD,
                             wherey[VTERM] - 1,
                             vscrn_c_page_margin_bot(VTERM) - 1,
                             1,
                             FALSE,
                             SP,
                             FALSE);
            }
            break;
        case 'l':
              if ( ISH19(tt_type_mode) ) {
                  /* Erase Entire Line */
                  clrline_escape(VTERM,SP);
              } else if ( ISSCO(tt_type_mode) || ISK95(tt_type_mode)
							|| ISXTERM(tt_type_mode) ) {
                  /* LMA - Lock Memory Area */
                  setmargins(wherey[VTERM],VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0));
                  lgotoxy(VTERM, relcursor ? vscrn_c_page_margin_left(VTERM) : 1,
                           relcursor ? vscrn_c_page_margin_bot(VTERM) : 1);
              }
              break;
        case 'M':                       
            /* RI - Reverse Index, VT102 */
            if (ISVT100(tt_type_mode)) {
                if (vscrn_c_page_margin_top(VTERM) == wherey[VTERM])
                    VscrnScrollPage(VTERM,
                                 DOWNWARD_SMOOTHLY,
                                 vscrn_c_page_margin_top(VTERM) - 1,
                                 vscrn_c_page_margin_bot(VTERM) - 1,
                                 vscrn_c_page_margin_left(VTERM) - 1,
                                 vscrn_c_page_margin_right(VTERM) - 1,
                                 1,
                                 FALSE,
                                 SP,
                                 vscrn_current_page_number(vmode, FALSE) );
                else if (tt_type == TT_VT100 || tt_type == TT_VT102) {
                    /* The VT10x and only the VT10x does not reset the
                     * LCF on RI. The VT220 and VT520 when emulating a VT100 do.
                     * cursorup() always resets the LCF, so take a backup before
                     * calling.
                     */
                    bool lcf = wrapit;
                    cursorup(0);
                    wrapit = lcf;
                }
                else {
                    cursorup(0);
                }
            }
            else if ( ISH19(tt_type_mode) && achar == 'M' ) {
                /* H19 - Delete Line */
                VscrnScroll(VTERM,
                             UPWARD,
                             wherey[VTERM] - 1,
                             vscrn_c_page_margin_bot(VTERM) - 1,
                                 1,
                                 FALSE,
                                 SP,
                             FALSE);
            }
            break;
        case 'm':
              if ( ISSCO(tt_type_mode) || ISK95(tt_type_mode)
					|| ISXTERM(tt_type_mode)  ) {
                  /* USR - Unlock Memory Area */
                  setmargins(1,VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0));
                  lgotoxy(VTERM, 1, 1);
              }
              break;
        case 'p':
            if ( ISH19(tt_type_mode) ) {
                /* Enter Reverse Video Mode */
                attrib.reversed = TRUE ;
            }
            break;
        case 'Q':               
            /* SCOANSI/AT386 Fn key assignments */
            /* Normally PU1 String.  SCOANSI break ANSI X.64-1979 */
            if ( ISANSI(tt_type_mode) )
            {
                int fn,quote, next, control=0 ;

                fn = ttinc(0) - '0' ;   /* get the Fn number */
                if ( fn < 0 ) {         /* illegal Fn */
					le_putchar(fn);
                    break;
				}

                if ( !savefiletext[0] )
                    strcpy(savefiletext,filetext);
                strcpy( filetext, "ANSI FN" ) ;
                VscrnIsDirty(VTERM) ;

                quote = ttinc(0) ;              /* get the Quote char */
#ifdef CK_APC
                apclength = 0 ;
                while ( (next = ttinc(0)) != quote &&
                        apclength < apcbuflen ) {
                    if ( control )
                    {
                        apcbuf[apclength++] = next-32 ;
                        control = 0 ;
                    }
                    else
                    {
                        if ( next == '^' )
                            control = 1 ;
                        else
                            apcbuf[apclength++] = next ;
                    }
				}
                apcbuf[apclength] = '\0' ;
#else /* CK_APC */
                while ( ttinc(0) != quote );
#endif /* CK_APC */
                if (savefiletext[0]) {          /* Fix status line */
                    strcpy(filetext,savefiletext);
                    savefiletext[0] = NUL;
                    VscrnIsDirty(VTERM);  /* status line needs to be updated */
                }

#ifdef CK_APC
#ifndef NOSETKEY
#ifndef NOKVERBS
                if ( next == quote )
                {
                    /* assign the string to the function key */
                    if ( udkfkeys[fn] ) {
                        free(udkfkeys[fn]) ;
                        udkfkeys[fn]=NULL;
                    }
                    if ( strlen(apcbuf) )
                        udkfkeys[fn] = strdup(apcbuf) ;
                }
#endif /* NOKVERBS */
#endif /* NOSETKEY */
#endif /* CK_APC */
            }
            break;
        case 'q':
            if ( ISH19(tt_type_mode) ) {
                /* Exit Reverse Video Mode */
                attrib.reversed = FALSE ;
            }
            break;
        case 'r':
            if ( ISH19(tt_type_mode) ) {
                /* Modify Baud Rate */
                /* we don't do this, just eat the next character */
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            }
            break;
        case 'S':
            if ( ISAAA(tt_type_mode) ) {
                /* STS - Set Transmit State */
            }
            break;
/*
  VT52 printer controls.  For now, autoprint is treated like transparent
  print.  32-bit version only, to avoid stack overflows in 16-bit version.
  Edit 190, fdc.
*/
        case 'u':
                if ( ISH19(tt_type_mode) ) {
                    /* Exit Keypad Shift Mode */
                    tt_shift_keypad = FALSE ;
                    break;
                }
        case 'V':                       
            if (ISVT52(tt_type_mode)) {/* VT52 control */
                /* Print cursor line */
                prtscreen(VTERM,wherey[VTERM],wherey[VTERM]);
            } else if ( ISAAA(tt_type_mode) ) {
                /* SPA - Start Protected Area */
            }
            break;
        case 'v':
                if ( ISH19(tt_type_mode) ) {
                    /* Wrap Around at End of Line */
                    tt_wrap = TRUE ;
                }
                break;
        case 'W':                       
            if (ISVT52(tt_type_mode)) { /* VT52 control */
                /* Transparent print on */
                turnonprinter = xprint = TRUE;
            } else if ( ISAAA(tt_type_mode) ) {
                /* EPA - End Protected Area */
            }
            break;
        case 'w':
                if ( ISH19(tt_type_mode) ) {
                    /* Discard at End of Line */
                    tt_wrap = FALSE ;
                }
                break;
        case 'X':                       /* Transparent print off */
            if (ISVT52(tt_type_mode)) { /* VT52 control */
                turnoffprinter = TRUE;
                xprint = FALSE ;
            }
            break;
        case 'x':
            if ( ISH19(tt_type_mode) ) {
                /* Set Modes */
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch ( achar ) {
                case '1':       /* Enable 25th line */
                    if ( !tt_status[VTERM] )
                        break;
                    settermstatus(FALSE);
                    break;
                case '2':       /* No Key Click */
                    setkeyclick(FALSE);
                    break;
                case '3':       /* Hold Screen Mode */
                    break;
                case '4':       /* Block Cursor */
                    tt_cursor = TTC_BLOCK ;
                    setcursormode() ;
                    break;
                case '5':       /* Cursor Off */
                    cursorena[VTERM] = FALSE ;
                    break;
                case '6':       /* Keypad Shifted */
                    tt_shift_keypad = TRUE ;
                    break;
                case '7':       /* Alternate keypad mode */
                    tt_keypad = TTK_APPL ;
                    break;
                case '8':       /* Auto Line Feed on receipt of CR */
                    tt_crd = TRUE ;
                    break;
                case '9':       /* Auto CR on receipt of LF */
                    tnlm = TRUE ;
                    break;
                }
            }
            break;
        case 'Y':                       /* Direct cursor address */
            if (ISVT52(tt_type_mode)) { /* VT52 control */
                int row,column ;
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                row = achar - 31;
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                column = achar - 31;
                lgotoxy(VTERM,column, row);
            }
            break;
        case 'y':
            if ( ISH19(tt_type_mode) ) {
                /* Reset Modes */
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                switch ( achar ) {
                case '1':       /* Disable 25th line */
                    if ( tt_status[VTERM] )
                        break;
                    settermstatus(TRUE);
                    break;
                case '2':       /* Key Click */
                    setkeyclick(TRUE);
                    break;
                case '3':       /* Exit Hold Screen Mode */
                    break;
                case '4':       /* Underline Cursor */
                    tt_cursor = TTC_ULINE ;
                    setcursormode() ;
                    break;
                case '5':       /* Cursor On */
                    cursorena[VTERM] = TRUE ;
                    break;
                case '6':       /* Keypad Unshifted */
                    tt_shift_keypad = FALSE ;
                    break;
                case '7':       /* Exit Alternate keypad mode */
                    tt_keypad = TTK_NORM ;
                    break;
                case '8':       /* No Auto Line Feed on receipt of CR */
                    tt_crd = FALSE ;
                    break;
                case '9':       /* No Auto CR on receipt of LF */
                    tnlm = FALSE ;
                    break;
                }
            }
            break;
        case 'Z':                       /* DECID - Identify Terminal */
            if ( ISVT52(tt_type_mode) ) {
                sendescseq(tt_info[TT_VT52].x_id);
            }
            else if ( ISVT220(tt_type) ) {
                sendescseq(tt_info[tt_type].x_id);
            }
            else if (tt_type_mode >= 0 && tt_type_mode <= max_tt) {
                sendescseq(tt_info[tt_type_mode].x_id);
            }
            break;
        case 'z':
            if ( ISH19(tt_type_mode) ) {
                doreset(1) ;
            }
            break;
        case ']':
            if ( ISH19(tt_type_mode) ) {
                /* Transmit 25th line to host */
				/* Note: If we were to ever support this, it would only be if
				   senddata is enabled - for security */
                ;
            }
            else if (ISVT52(tt_type_mode)) /* VT52 control */
                /* Print screen */
                prtscreen(VTERM,1,VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0));
            break;
        case '^':                       /* Autoprint on */
              if (ISVT52(tt_type_mode)) {/* VT52 control */
                  turnonprinter = TRUE;
                  setaprint(TRUE);
              }
            break;
        case '_':                       /* Autoprint off */
            if (ISVT52(tt_type_mode)) { /* VT52 control */
                turnoffprinter = TRUE;
                setaprint(FALSE);
            }
            break;
        case '#':
            if ( ISH19(tt_type_mode) ) {
                /* Transmit Page (lines 1-24) to Host */
                break;
            }
            /* Esc # sequence */
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
            switch (achar) {
            case '3': /* DECDHL */
				if (!declrmm) {
                	decdwl_escape(VT_LINE_ATTR_DOUBLE_WIDE |
                                  VT_LINE_ATTR_DOUBLE_HIGH |
                                  VT_LINE_ATTR_UPPER_HALF );
				}
                break;
            case '4': /* DECDHL */
				if (!declrmm) {
                    decdwl_escape(VT_LINE_ATTR_DOUBLE_WIDE |
                                  VT_LINE_ATTR_DOUBLE_HIGH |
                                  VT_LINE_ATTR_LOWER_HALF);
				}
                break;
            case '5': /* DECSWL */
				if (!declrmm) {
                    decdwl_escape(VT_LINE_ATTR_NORMAL);
				}
                break;
            case '6': /* DECDWL */
				if (!declrmm) {
                	decdwl_escape(VT_LINE_ATTR_DOUBLE_WIDE);
				}
                break;
            case '7': /* Hardcopy (vt100) */
                break;
            case '8': /* DECALN - Screen Alignment Display */
                {
                    videoline * line ;
                    viocell cell;
                    short x,y ;

                    /* STD 070 says we reset SGR attributes, though no hardware
                     * terminals tested do this. DECterm does though. */
                    if (ISK95(tt_type_mode) || ISDECTERM(tt_type_mode)) {
                        attrib.blinking = FALSE;
                        attrib.italic = FALSE;              /* No italic */
                        attrib.bold = FALSE;
                        attrib.invisible = FALSE;
                        attrib.underlined = FALSE;
                        attrib.reversed = FALSE;
                        attrib.dim = FALSE ;
                        attrib.graphic = FALSE ;
                        attrib.wyseattr = FALSE ;
                        attrib.crossedout = FALSE ;
                        attrib.erased = FALSE;
                        attrib.hyperlink = FALSE;
                        attrib.linkid = 0;
                        resetcolors(0);
                    }

                    cell.c = 'E';
                    cell.video_attr = defaultattribute; /* was 0x07 */
                    /* Self Test */
                    /* 24 lines of MAXTERMCOL cols of cells */
                    for ( y=0 ; y < 24 ; y++ ) {
                        line = VscrnGetLineFromTop(VTERM, y, FALSE) ;
                        for ( x=0 ; x < MAXTERMCOL ; x++ ) {
                            line->cells[x] = cell ;
                            line->vt_char_attrs[x] = VT_CHAR_ATTR_NORMAL;
                        }
                        line->vt_line_attr = VT_LINE_ATTR_NORMAL;
                    }
                    setmargins(1, VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0));

                    relcursor=FALSE;

                    /* Note: Only the VT5xx does this: the VT420 probably
                     * *should*, but it doesn't */
                    set_declrmm(FALSE);  /* TODO: Not if TT_VT420? */


                    if ( decsasd == SASD_STATUS )
                        lgotoxy( VSTATUS, 1, 1 );
                    else
                        lgotoxy(VTERM,1, 1);
                    if (cursor_on_visible_page(VTERM)) {
                        VscrnIsDirty(VTERM);
                    }
                }
                break;
            case ':':   /* WYDHL */
                decdwl_escape(VT_LINE_ATTR_DOUBLE_HIGH |
                               VT_LINE_ATTR_UPPER_HALF);
                break;
            case ';':   /* WYDHL */
                decdwl_escape(VT_LINE_ATTR_DOUBLE_HIGH |
                               VT_LINE_ATTR_LOWER_HALF);
                break;
            default:
                break;
            } /* Esc # sequence */
            break;

        case '=':                       /* Application mode */
            tt_keypad = TTK_APPL;
            break;
        case '>':                       /* Numeric mode */
            tt_keypad = TTK_NORM;
            break;
        case '<':                       /* Enter ANSI mode */
            /* VT52 control */
            if (ISVT52(tt_type_mode) && tt_type != TT_VT52 ) {
                if ( ISH19(tt_type) )
                    tt_type_mode = TT_VT100 ;
                else {
#ifdef COMMENT
                    tt_type_mode = tt_type_vt52;
#else /* COMMENT */
                    /* As per dickey@clark.net */
                    tt_type_mode = TT_VT102 ;
#endif /* COMMENT */
                }
                ipadl25();
            }
            break;

        case '(':                       /* Select 94 Character Set into G0 */
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
              if ( ISLINUX(tt_type_mode) ) {
#ifndef COMMENT
                  /* From man "console_codes" as of Red Hat 8.0
                   *  ESC (    Start sequence defining G0 character set
                   *  ESC ( B     Select default (ISO 8859-1 mapping)
                   *  ESC ( 0     Select vt100 graphics mapping
                   *  ESC ( U     Select null mapping - straight to character ROM
                   *  ESC ( K     Select user mapping - the map that is loaded by
                   *              the utility mapscrn(8).
                   *  ESC )    Start sequence defining G1
                   *           (followed by one of B, 0, U, K, as above).
                   */
                  charset( cs94, achar, &G[0]) ;
#else
                  /* Linux only has two 256 char character sets */
                  /* We simulate them by using G0 for ASCII and */
                  /* G2 as Linux-G0 and G3 as Linux-G1          */
                  charset( cs94, achar, &G[3]) ;
#endif /* COMMENT */
              } else {
                  if ( decnrcm && isNRC(achar))
                  {
                      for ( i=0; i<=3 ; i++ )
                          charset( cs94, achar, &G[i] ) ;
                  }
                  else
                  {
                      charset( cs94, achar, &G[0] ) ;
                  }
            }
            break;
        case ')':                       /* Select 94 Character Set into G1 */
            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
              if ( ISLINUX(tt_type_mode) ) {
#ifndef COMMENT
                  /* From man "console_codes" as of Red Hat 8.0
                   *  ESC (    Start sequence defining G0 character set
                   *  ESC ( B     Select default (ISO 8859-1 mapping)
                   *  ESC ( 0     Select vt100 graphics mapping
                   *  ESC ( U     Select null mapping - straight to character ROM
                   *  ESC ( K     Select user mapping - the map that is loaded by
                   *              the utility mapscrn(8).
                   *  ESC )    Start sequence defining G1
                   *           (followed by one of B, 0, U, K, as above).
                   */
                  charset( cs94, achar, &G[0]) ;
#else /* COMMENT */
                  /* Linux only has two 256 char character sets */
                  /* We simulate them by using G0 for ASCII and */
                  /* G2 as Linux-G0 and G3 as Linux-G1          */
                  charset( cs94, achar, &G[3]) ;
#endif /* COMMENT */
              } else {
                  if ( decnrcm && isNRC(achar) )
                  {
                      for ( i=0; i<=3 ; i++ )
                          charset( cs94, achar, &G[i] ) ;
                  }
                  else
                  {
                      charset( cs94, achar, &G[1] ) ;
                  }
            }
            break;
        case '*':  /* Select 94 Character Set into G2 */
              if ( !ISLINUX(tt_type_mode) &&
                   (ISVT220(tt_type_mode) || ISANSI(tt_type_mode))) {
                  achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                  if ( decnrcm && isNRC(achar) )
                  {
                      for ( i=0; i<=3 ; i++ )
                          charset( cs94, achar, &G[i] ) ;
                  }
                  else
                  {
                      charset( cs94, achar, &G[2] ) ;
                  }
              }
              break;
        case '%':       /* Non-ISO 2022 character sets */
              achar = (escnext<=esclast)?escbuffer[escnext++]:0;
              switch ( achar ) {
              case '@':         /* Return to ISO 2022 mode */
                  tt_utf8 = 0;
                  break;
              case 'G':         /* UTF-8 with standard return */
                  tt_utf8 = 1;
                  break;
              }
              break;
        case '+':                       /* Select 94 Character Set into G3 */
              if ( !ISLINUX(tt_type_mode) &&
                   (ISVT220(tt_type_mode) || ISANSI(tt_type_mode))) {
                  achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                  if ( decnrcm && isNRC(achar) )
                  {
                      for ( i=0; i<=3 ; i++ )
                          charset( cs94, achar, &G[i] ) ;
                  }
                  else
                  {
                      charset( cs94, achar, &G[3] ) ;
                  }
              }
              break;

        case '-':                       /* Select 96 Character Set into G1 */
              achar = (escnext<=esclast)?escbuffer[escnext++]:0;
              charset( cs96, achar, &G[1] ) ;
              break;
        case '.':                       /* Select 96 Character Set into G2 */
              if ( ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                  charset( cs96, achar, &G[2] ) ;
              }
              break;
        case '/':                       /* Select 96 Character Set into G3 */
              if ( ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                  charset( cs96, achar, &G[3] ) ;
              }
              break;

        case '~':                       /* Lock shift G1, right */
              if ( ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  GR = &G[1] ;
              }
              break;
        case '}':                       /* Lock shift G2, right */
              if (ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  GR = &G[2] ;
              }
              else if ( ISH19(tt_type_mode) ) {
                  /* Keyboard Disabled */
                  keylock = TRUE ;
              }
              break;
        case 'n':
              if ( ISH19(tt_type_mode) ) {
                  /* Cursor Position Report */
                  char buf[12] ;
                  sprintf(buf,"%cY%c%c",ESC,wherey[VTERM]+31,wherex[VTERM]+31);
                  sendchars(buf,strlen(buf));
              }
              else if ( ISVT220(tt_type_mode)  || ISANSI(tt_type_mode)) {
                  /* Lock shift G2, left */
                  GL = &G[2] ;
              }
              break;
        case 'o':                       /* Lock shift G3, left */
              if (ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  GL = &G[3] ;
              }
              else if ( ISH19(tt_type_mode) ) {
                  /* Erase Beginning of Line */
                  clrbol_escape(VTERM,SP);
              }
              break;
        case '|':                       /* Lock shift G3, right */
              if (ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  GR = &G[3] ;
              }
              break;
        case 'N':                       /* Single shift G2, left */
              if (ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  SSGL = &G[2] ;
              }
              else if ( ISH19(tt_type_mode) ) {
                  /* H19 - Delete Character */
                  blankvcell.c = SP;
                  blankvcell.video_attr = geterasecolor(VTERM);
                  if (pn[1] > VscrnGetWidth(VTERM) + 1 -
                       wherex[VTERM])
                      pn[1] = VscrnGetWidth(VTERM) + 1 -
                          wherex[VTERM];
                  VscrnScrollLf(VTERM, wherey[VTERM] - 1,
                                 wherex[VTERM] - 1,
                                 wherey[VTERM] - 1,
                                 VscrnGetWidth(VTERM) - 1,
                                 pn[1],
                                 blankvcell
                                 ) ;

              }
              break;
        case 'O':                       /* Single shift G3, left */
              if (ISVT220(tt_type_mode) || ISANSI(tt_type_mode)) {
                  SSGL = &G[3] ;
              }
              else if ( ISH19(tt_type_mode) ) {
                  /* Exit Insert Character Mode */
                  insertmode = FALSE ;
              }
              break;

        case '{':
                if ( ISH19(tt_type_mode) ) {
                    /* Keyboard Enabled */
                    keylock = FALSE ;
                    break;
                }
                break;
        default:
            if (achar == 12) {  /* ESC Ctrl-L */
                if ( decsasd == SASD_STATUS ) {
                    lgotoxy( VSTATUS, 1, 1 );
                    clrscreen(VSTATUS,SP);
                }
                else {
                    lgotoxy(VTERM,1, 1);
                    clrscreen(VTERM,SP);
                }
            }
            break;
        } /* First Level Case  */
    }
    else {                              /* transparent print */
        switch (achar) {                /* First Level */
          case '[':                     /* CSI */
            {
                achar = (escnext<=esclast)?escbuffer[escnext++]:0;
              LB3000:
                switch (achar) {        /* Second level */
                  case '?':             /* DEC private */
                    private = TRUE;
                    achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                    goto LB3000;
                    break;
                  default:              /* Pn - got a number */
                  /*LB3001:*/
                    {                   /* Esc [ Pn...Pn x   functions */
                        pn[1] = pnumber(&achar);
                        k = 1;
                      /*LB3002:*/
                        while (achar == ';') { /* get Pn[k] */
                            achar = (escnext<=esclast)?escbuffer[escnext++]:0;
                            k++;
                            if (achar == '?')
                              achar =
                                (escnext<=esclast)?escbuffer[escnext++]:0;
                            pn[k] = pnumber(&achar);
                        }
                        pn[k + 1] = 1;
                      //*LB3003:
                        switch (achar) { /* Third level */
                          case 'i':     /* Media Copy */
                            switch (pn[1]) {
                            case  4:
                                if ( private == FALSE ) {
                                    xprint = FALSE;
                                }
                                if ( is_noprint() )
                                  turnoffprinter = TRUE;
                                break;
                            case 5:
                                if ( private == FALSE )
                                    return ; /* Don't print this */
                                break;
                            case 7:
                                if ( !xprint && private == FALSE) {
                                    /* Turn on screen display */
                                    screenon = TRUE;
                                    if ( savefiletext[0] ) {
                                        strcpy(filetext,savefiletext);
                                        savefiletext[0] = NUL ;
                                        /* Update status line */
                                        VscrnIsDirty(VTERM);
                                    }
                                }
                                break;
                            }
                        }
                    }
                    break;
                }
            }                   /* Left square bracket */
            break;
        } /* First Level Case  */
    } /* transparent print || screen off */

    /* Host said to turn off the printer. */

    if (turnoffprinter) {
        printeroff();
        turnoffprinter = FALSE;
    }

/* If printer is in User or Controller modes, print this escape sequence. */
/* but not if Auto print mode */

    if ( printon && (is_xprint() || is_uprint())) {
        switch(escbuffer[0]) {
        case _CSI:
            prtchar(_CSI);
            i = 2;
            break;
        case ESC:
        default:
            i=0;;
            break;
        }
        if (esclast > 0) {
            /* print esc sequence */
            for (; i <= esclast; ++i)
                prtchar(escbuffer[i]);
        }
    }
/*
  If we just got a "printer on" directive, turn on the printer now.
  This way, the "printer on" directive itself is not printed.
*/
    if (turnonprinter) {                /* Last command was "printer on" */
        printeron();
        turnonprinter = FALSE;
    }
    if ( xprint == FALSE )
      VscrnIsDirty(VTERM);
}

/* ================================================================== */
/* VT100  -  emulate a DEC VT terminal writing a character            */
/* ================================================================== */
void
vt100(unsigned short vtch) {
    int             i;
    viocell       cell ;
    int vmode = decsasd == SASD_TERMINAL ? VTERM : VSTATUS ;

#ifdef COMMENT
    debug(F101,"vt100","",vtch);
#endif /* COMMENT */

   if (tt_type_mode == TT_NONE) {
      wrtch(vtch);
      return;
   } else if (!xprint) {
      if (vtch < 32 &&                  /* Control Character */
          (!crm && !literal_ch)) {      /* no display of c0 control chars */
         achar = vtch;  /* Let the rest of this module see the value */
         switch (achar) {
         case FF:                       /* Formfeed */
             if ( ISSUN(tt_type_mode) ) {
                 clrscreen(vmode,SP);
                 lgotoxy(vmode,1,1);       /* and home the cursor */
                 VscrnIsDirty(vmode);
             }
             else if ( (IS97801(tt_type_mode) || ISHP(tt_type_mode)) ) {
                 if (wherex[vmode] < vscrn_c_page_margin_right(vmode))
                     wherex[vmode]++;
             }
             else if ( ISANSI(tt_type_mode) ) {
                 if ( ISAVATAR(tt_type_mode) )  /* Avatar */
                     attribute = defaultattribute ;
                 clrscreen(vmode,SP);
                 lgotoxy(vmode,1,1);       /* and home the cursor */
                 VscrnIsDirty(vmode);
             }
             else {
                 wrtch((char) LF);
             }
             break;
         case LF:                       /* Linefeed */
         case VT:                       /* Vertical tab */
             wrtch((char) LF);
             break;
         case CK_CR:                       /* Carriage return */
             wrtch((char) achar);
             break;
         case SO:                       /* SO */
             /* If I read the Linux Console Codes doc right, this is the proper behavior */
             if ( ISLINUX(tt_type_mode) ) {
                 GR = &G[3];
             } else if ( !ISANSI(tt_type_mode) )       { /* "ANSI music" protection... */
                 GL = &G[1] ;
             }
             break;

         case SI:                       /* SI */
             /* ditto */
             if ( ISLINUX(tt_type_mode) ) {
                 GR = &G[2];
             } else if ( !ISANSI(tt_type_mode) )       { /* Ditto, gag... */
                 GL = &G[0] ;
             }
             break;

         case BS:                       /* BS */
             wrtch((CHAR) achar);
             break;

         case BEL:                      /* BEL */
             bleep(BP_BEL);
             break;

         case ENQ:                      /* ENQ */
             if ( ISVIP(tt_type_mode) ) {
                 sendescseq("7813  P GC  A\003");
             }
             else if (tt_answer)
                 sendchars(answerback,strlen(answerback)) ;
             break;
         case HT:               /* Horizontal tab */
             if (tt_type_mode == TT_VT220 || tt_type_mode == TT_VT220PC) {
                 /* The VT220, and only the VT220, clears the last column flag
                  * on TAB. STD-070 says it should too, but given all later
                  * terminals don't do this I guess DEC decided it was a bad
                  * idea. */
                 wrapit = FALSE;
             }
             cursortab(1);
             break;
         case SYN:      /* Ctrl-V - AVATAR AVTCODE */
             if ( ISAVATAR(tt_type_mode) )
                 avatar() ;
             break;
         case XEM:       /* AVATAR - Repeat character */
             if ( ISAVATAR(tt_type_mode) ) {
                 int ch, count;
                 ch = avainc(0) ;
                 count = avainc(0) ;
                 if ( debses )
                     break;
                 while ( count-- )
                     wrtch(ch);
             }
             break;
         case NUL:
             if ( IS97801(tt_type_mode) )
                 wrtch(SP);
             break;
         default:               /* ignore it */
             break;
         }
            /* End of Control Character */
      } else {
         if (vtch != DEL) {             /* Normal character. */
            int rmargin = cursor_right_margin(vmode);

            if (ISVT100(tt_type_mode)) {
                if ( vtch == 35 &&
                     GNOW->designation == TX_BRITISH &&
                     tcsr == TX_ASCII )
                {
                    /* UK ISO 646 character-set, # = Pound Sterling Sign */
                    vtch = 156;
                }
            } else {
                if (vt52graphics) {
                    if ( ISH19(tt_type) && (94 <= vtch) && (vtch <= 126)) {
                       literal_ch = TRUE ;
                        vtch = xlh19grph(vtch) ;
                    }
                    else if ((95 <= vtch) && (vtch <= 126)) {
                        literal_ch = TRUE;
                        vtch = xldecgrph(vtch);
                    }
                }
            }

            /* On the right margin? */
            if (wherex[vmode] != rmargin)
            {
                wrtch(vtch);    /* Not on right margin */
                wrapit = FALSE;
            } else {            /* On right margin. */
                if (wrapit) {   /* Time to wrap?  */
                    if (literal_ch) {
                        literal_ch = 0;
                        wrtch(CK_CR);
                        wrtch(LF);
                        literal_ch = 1;
                    } else {
                        wrtch(CK_CR);
                        wrtch(LF);
                    }
                    wrtch(vtch);        /* Now write the character */
                    wrapit = FALSE;     /* Remember wrapping is done */
                } else {                /* Not time to wrap */
                    cell.c = vtch;
                    cell.video_attr = attribute ;
                    VscrnWrtCell(vmode, cell,attrib,wherey[vmode]-1, rmargin-1);
                    if (cursor_on_visible_page(VTERM)) {
                        VscrnIsDirty(VTERM);
                    }
                    literal_ch = FALSE;
                    if (tt_wrap) { /* If TERM WRAP ON */
                        if ( IS97801(tt_type_mode) ) {
                            if ( wherey[vmode] == vscrn_c_page_margin_bot(VTERM) ) {
                                if ( !sni_pagemode ) {
                                    wrtch(CK_CR);
                                    wrtch(LF);
                                }
                                else {  /* Page Mode */
                                    lgotoxy(vmode,1,1);
                                }
                            }
                            else {
                                wrtch(CK_CR);
                                wrtch(LF);
                            }
                        } else /* if ( !deccolm ) */ {
							/* 20050407 - I do not remember why there is a test
							 * to disable wrapping if 132 column mode is on.
							 * If there was such a exclusion it must be restricted
							 * to a particular model of terminal.  Which one?
							 */
                            if ( (ISLINUX(tt_type_mode) ||
                                  ISVT100(tt_type_mode) ||
                                  ISVT52(tt_type_mode)) &&
                                  !ISHFT(tt_type_mode))
                                wrapit = TRUE ; /* need to wrap next time */
                            else {
                                wrtch(CK_CR);
                                wrtch(LF);
                            }
                        }
                    }
                }
            }
         }                      /* End Normal char */
      }
   }
   if (is_xprint() || (is_uprint() && (vtch != 27)))
       prtchar(vtch) ;
}

#ifdef CK_APC
void
apc_command(int type, char * cmd)
{
    extern struct mtab *mactab;             /* Macro table */
    extern int nmac;
#ifdef DCMDBUF
    extern struct cmdptr *cmdstk;
#else
    extern struct cmdptr cmdstk[];
#endif /* DCMDBUF */

    debug(F111,"apc_command",cmd,type);
    if ( cmd == NULL )
        return;
    if ( cmd != apcbuf )
        ckstrncpy(apcbuf,cmd,APCBUFLEN);
    apcactive = type;
    apclength = strlen(apcbuf) ;
    apccmd = 0;

    if (apcstatus & APC_NOINP) {
        debug(F110,"apc_command (no input) about to execute APC",apcbuf,0);
        domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
        debug(F110,"apc_command finished executing APC",apcbuf,0);
        delmac("_apc_commands",1);
        cmini(ckxech);
        if ( apcactive == APC_INACTIVE || apccmd
#ifndef NOXFER
             || (apcactive == APC_LOCAL && !xferstat && adl_err != 0)
#endif /* NOXFER */
             )
            SetConnectMode(FALSE,CSX_APC); /* exit from terminal emulator */
        return;
    }

    debug(F111,"apc_command","tt_async",tt_async);
    if ( tt_async ) {
        if (mlook(mactab,"_apc_commands",nmac) == -1) {
            int vmsave = vmode;
            SaveTermMode(wherex[VTERM],wherey[VTERM]);
            RestoreCmdMode();
            concooked();
            debug(F110,"apc_command about to execute APC",apcbuf,0);
            domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
            debug(F110,"apc_command finished executing APC",apcbuf,0);
            delmac("_apc_commands",1);
            cmini(ckxech);
            conraw();
            RestoreTermMode();
            vmode = vmsave;
            VscrnIsDirty(VCMD);
            VscrnIsDirty(vmode);
            if ( apcactive == APC_INACTIVE || apccmd
#ifndef NOXFER
                 || (apcactive == APC_LOCAL && !xferstat && adl_err != 0)
#endif /* NOXFER */
                 )
                SetConnectMode(FALSE,CSX_APC); /* exit from terminal emulator */
        }
        apcactive = APC_INACTIVE;
    } else {
        term_io = FALSE;                /* Disable Emulator I/O */
        SetConnectMode(FALSE,CSX_APC);  /* exit from terminal emulator */
    }
}
#endif /* CK_APC */
#endif /* NOTERM */
#endif /* NOLOCAL */
