/*======================================================================*\
|*		Editor mined						*|
|*		operating system dependent I/O				*|
\*======================================================================*/

#include "mined.h"
#include "io.h"
#include "termprop.h"


#ifdef ANSI
#undef conio
#endif


#include <errno.h>
#include <signal.h>

/* include configuration for SIGWINCH information retrieval */
#ifdef TERMIO
#define include_TERMIO
#endif
#ifdef SGTTY
#define include_SGTTY
#endif


/* terminal handling selection */
#ifdef CURSES
#include <curses.h>
# undef FALSE
# undef TRUE

#ifdef SETLOCALE
#include <locale.h>
#endif

/* ensure window size detection capability */
# ifndef SGTTY
# define include_TERMIO
# endif

# undef TERMIO	/* \ must be  */
# undef SGTTY	/* / disabled */
#endif


#ifdef include_TERMIO
# ifdef questionable_but_recommended_by_some_SuSe_Guru_doesnt_work_on_HP
#  if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1))
#	include <termios.h>		/* define POSIX.1 termios */
#	include <sys/ioctl.h>		/* declare ioctl() for winsize */
#	undef   TCGETS		/* Use POSIX.1 instead */
#  else
/* Compatible <termio.h> for old 'struct termio' ioctl interface. */
#	include <termio.h>
#  endif
# else
#	include <termios.h>		/* define POSIX.1 termios */
#	include <sys/ioctl.h>		/* declare ioctl() for winsize */
# endif
#endif

#ifdef include_SGTTY
#include <sys/ioctl.h>
#include <sgtty.h>
/* #include <sys/ttold.h> */
/*extern int ioctl ();*/
#endif


#ifdef __CYGWIN__
#include <sys/ioctl.h>
#endif

#ifdef SIGPHONE		/* this trick was taken from less' screen.c */
#include <sys/window.h>	/* for window size detection */
#endif

#ifdef msdos
#define _getch_
#endif

#ifdef msdos
/* make REGS "x." branch work with djgpp */
#define _NAIVE_DOS_REGS
#include <dos.h>
#ifndef __TURBOC__
#include <dpmi.h>
#include <go32.h> /* define transfer buffer __tb and function dosmemget */
#endif
#endif

#ifdef unix
# undef _POSIX_SOURCE
# undef _XOPEN_SOURCE
#define selectread	/* use select () ? */
#endif
#ifndef __TURBOC__
#include <sys/time.h>	/* for struct timeval (for select in inputreadyafter) */
#endif

#ifdef vms
#include <socket.h>	/* for select () and struct timeval */
# ifdef CURSES
# define _getch_
# endif
#endif

#ifdef __EMX__
#undef selectread
# ifdef CURSES
# define _getch_
# endif
#endif

#ifdef CURSES_INPUT	/* currently not defined */
#define _getch_	/* not necessarily needed for Unix, but might be better 
		   with new curs_readchar loop in inputreadyafter () */
#endif

#ifdef _getch_
#ifndef CURSES
extern int getch ();
#endif
#endif


#ifdef msdos

#ifndef __TURBOC__
#undef unix
/* don't #define ANSI */
#endif

#ifndef conio
#define ANSI
#endif

#endif


/*======================================================================*\
|*			Mode indication					*|
\*======================================================================*/

/* terminal capabilites and feature usage */
FLAG can_scroll_reverse = True;
FLAG can_add_line = True;
FLAG can_delete_line = True;
FLAG can_clear_eol = True;
FLAG can_erase_chars = True;
FLAG can_reverse_mode = True;
FLAG can_hide_cursor = False;
FLAG can_dim = False;
FLAG can_alt_cset = True;
FLAG use_mouse_hilite_tracking = False;
FLAG use_mouse_button_event_tracking = True;
FLAG colours_256 = False;
FLAG colours_88 = False;
FLAG ansi_esc = True;
FLAG standout_glitch = False;
FLAG use_appl_cursor = True;
FLAG use_appl_keypad = False;

/* menu border style */
FLAG use_ascii_graphics = False;	/* use ASCII graphics for borders */
FLAG use_vga_block_graphics = False;	/* charset is VGA with block graphics */
FLAG use_pc_block_graphics = False;	/* alternate charset is VGA with block graphics */
FLAG use_vt100_block_graphics = False;
char menu_border_style = 'r';
int menumargin = 0;
FLAG explicit_border_style = False;
FLAG explicit_scrollbar_style = False;
FLAG use_stylish_menu_selection = True;
#define use_normalchars_boxdrawing ((utf8_screen || use_ascii_graphics) && ! use_vt100_block_graphics && ! use_vga_block_graphics)

int
use_unicode_menubar ()
{
  if (use_stylish_menu_selection
      && use_normalchars_boxdrawing
      && ! use_ascii_graphics
      && menu_border_style != '@') {
	return 1 + (menu_border_style == 'd');
  } else {
	return 0;
  }
}

/* feature usage options */
FLAG use_script_colour = True;
FLAG use_mouse = True;
FLAG use_mouse_anymove_inmenu = False;
FLAG use_mouse_anymove_always = False;
FLAG use_bold = True;
FLAG use_bgcolor = True;
FLAG avoid_reverse_colour = False;
FLAG use_modifyOtherKeys = False;
FLAG blink_cursor = False;

/* state */
static FLAG in_menu_mouse_mode = False; /* used in dosmouse.c */
FLAG in_menu_border = False;
int current_cursor_y = 0;
static FLAG is_mouse_hilite_mode_enabled = False;
static FLAG is_mouse_button_event_mode_enabled = False;

/* screen attributes: ANSI sequences */
char * markansi;		/* line indicator marking (dim/red) */
char * emphansi;		/* status line emphasis mode (red bg) */
char * borderansi;		/* menu border colour (red) */
char * selansi;			/* menu selection */
char * selfgansi;		/* menu selection background */
char * ctrlansi;		/* Control character display */
char * uniansi;			/* Unicode character display */
char * unimarkansi;		/* Unicode (lineend) marker display */
char * combiningansi;		/* combining character display */
char * menuansi;		/* menu line */
char * HTMLansi;		/* HTML display */
char * diagansi;		/* dialog (bottom status) line */
char * scrollfgansi;		/* scrollbar foreground */
char * scrollbgansi;		/* scrollbar background */

static int colour_token = -1;

void
set_colour_token (token)
  int token;
{
	colour_token = token;
}


/*======================================================================*\
|*			Unix signalling routines			*|
\*======================================================================*/

#define dont_debug_winchg


void
catch_signals (catchfunc)
  signalfunc catchfunc;
{
#ifdef SIGHUP
  signal (SIGHUP, catchfunc);
#endif
#ifdef SIGILL
  signal (SIGILL, catchfunc);
#endif
#ifdef SIGTRAP
  signal (SIGTRAP, catchfunc);
#endif
#ifdef SIGABRT
  signal (SIGABRT, catchfunc);
#endif
#ifdef SIGEMT
  signal (SIGEMT, catchfunc);
#endif
#ifdef SIGFPE
  signal (SIGFPE, catchfunc);
#endif
#ifdef SIGBUS
  signal (SIGBUS, catchfunc);
#endif
#ifdef SIGSEGV
  signal (SIGSEGV, catchfunc);
#endif
#ifdef SIGSYS
  signal (SIGSYS, catchfunc);
#endif
#ifdef SIGPIPE
  signal (SIGPIPE, catchfunc);
#endif
#ifdef SIGALRM
  signal (SIGALRM, catchfunc);
#endif
#ifdef SIGTERM
  signal (SIGTERM, catchfunc);
#endif
#ifdef SIGXCPU
  signal (SIGXCPU, catchfunc);
#endif
#ifdef SIGXFSZ
  signal (SIGXFSZ, catchfunc);
#endif
#ifdef SIGVTALRM
  signal (SIGVTALRM, catchfunc);
#endif
#ifdef SIGPROF
  signal (SIGPROF, catchfunc);
#endif
#ifdef SIGLOST
  signal (SIGLOST, catchfunc);
#endif
#ifdef SIGUSR1
  signal (SIGUSR1, catchfunc);
#endif
#ifdef SIGUSR2
  signal (SIGUSR2, catchfunc);
#endif
#ifdef SIGUSR3
  signal (SIGUSR3, catchfunc);
#endif
}

#ifdef SIGTSTP
FLAG cansuspendmyself = True;
#else
FLAG cansuspendmyself = False;
#endif

void
suspendmyself ()
{
#ifdef SIGTSTP
  kill (getpid (), SIGTSTP);
#endif
}

#ifdef SIGWINCH
/*
 * Catch the SIGWINCH signal sent to mined.
 */
static
void
catchwinch (dummy)
  int dummy;
{
  winchg = True;
  interrupted = True;
#ifdef debug_winchg
  printf ("winchg\n");
#endif

/* This is now performed in __readchar () to prevent display garbage 
   in case this interrupts occurs during display output operations which 
   get screen size related values changed while relying on them.
  if (waitingforinput) {
	RDwin ();
  }
*/

  signal (SIGWINCH, catchwinch); /* Re-installation of the signal */
  kill (getppid (), SIGWINCH);	/* propagate to parent (e.g. shell) */
}
#endif

#ifdef SIGQUIT
/*
 * Catch the SIGQUIT signal (^\) sent to mined. It turns on the quitflag.
 */
static
void
catchquit (dummy)
  int dummy;
{
#ifdef UNUSED /* Should not be needed with new __readchar () */
/* Was previously needed on Sun but showed bad effects on Iris. */
  static char quitchar = '\0';
  if (waitingforinput) {
	/* simulate input to enable immediate break also during input */
	(void) ioctl (input_fd, TIOCSTI, & quitchar);
  }
#endif
  quit = True;
  signal (SIGQUIT, catchquit); /* Re-installation of the signal */
}
#endif

#ifdef SIGBREAK
/*
 * Catch the SIGBREAK signal (control-Break) and turn on the quitflag.
 */
static
void
catchbreak (dummy)
  int dummy;
{
  quit = True;
  signal (SIGBREAK, catchbreak); /* do we need this ? */
}
#else
# ifdef msdos
static
int
controlbreak ()
{
  quit = True;
  return 1; /* continue program execution */
}
# endif
#endif

#ifdef SIGINT
/*
 * Catch the SIGINT signal (^C) sent if it cannot be ignored by tty driver
 */
static
void
catchint (dummy)
  int dummy;
{
  intr_char = True;
  signal (SIGINT, catchint); /* Re-installation of the signal */
}
#endif


/*======================================================================*\
|*			Unix terminal capabilities			*|
\*======================================================================*/

#ifdef unix

static char * cMouseX10On = "\033[?9h";
static char * cMouseX10Off = "\033[?9l";
static char * cMouseButtonOn = "\033[?1000h";
static char * cMouseButtonOff = "\033[?1000l";
static char * cMouseHighlightOn = "\033[?1001h";
static char * cMouseHighlightOff = "\033[?1001l";
static char * cMouseEventBtnOn = "\033[?1002h";
static char * cMouseEventBtnOff = "\033[?1002l";
static char * cMouseEventAnyOn = "\033[?1003h";
static char * cMouseEventAnyOff = "\033[?1003l";
static char * cMouseFocusOn = "\033[?1004h";
static char * cMouseFocusOff = "\033[?1004l";
static char * cMouseAmbigOn = "\033[?7700h";
static char * cMouseAmbigOff = "\033[?7700l";


/**
   termcap/termlib API and storage
 */
#define TERMCAP	/* disable to use termlib/terminfo API */

#ifdef CURSES
#undef TERMCAP
#endif


#ifdef TERMCAP

#define term_setup(TERM)	(tgetent (term_rawbuf, TERM) == 1)
#define term_getstr(tc, ti)	tgetstr (tc, & term_capbufpoi)
#define term_getnum(tc, ti)	tgetnum (tc)
#define term_getflag(tc, ti)	tgetflag (tc)

#else	/* TERMCAP */

#define term_setup(TERM)	(setterm (TERM) == 0)
#define term_getstr(tc, ti)	tigetstr (ti)
#define term_getnum(tc, ti)	tigetnum (ti)
#define term_getflag(tc, ti)	tigetflag (ti)

#endif	/* TERMCAP else */


#ifndef CURSES

#ifdef TERMCAP

extern int tgetent _((char * rawbuf, char * TERM));
extern char * tgetstr _((char *, char * * capbufpoi));
extern int tgetnum _((char *));
extern int tgetflag _((char *));

#define term_capbuflen 1024
static char term_capbuf [term_capbuflen];
static char * term_capbufpoi = term_capbuf;

#else	/* TERMCAP */

#ifdef BSD
extern int setterm _((char * TERM));
#else
extern int setupterm _((char * TERM, int , int *));
#define setterm(TERM)	setupterm (TERM, 1, 0)
#endif
extern char * tigetstr _((char *));
extern int tigetnum _((char *));
extern int tigetflag _((char *));

#endif	/* TERMCAP else */


extern char * tgoto _((char *, int, int));
extern int tputs _((char *, int, intfunc));
#define termputstr(str, aff)	(void) tputs (str, aff, (intfunc) __putchar)

static char * cCL, * cCE, * cEC, * cSR, * cAL, * cDL, * cCS, * cSC, * cRC,
     * cCM, * cSO, * cSE, * cVS, * cVE, * cVI,
     * cTI, * cTE, * cKS, * cKE,
     * cAS, * cAE, * cEA, * cAC, * cS2, * cS3,
     * cME, * cMR, * cMH, * cMD, * cMB,
     * cAF, * cAB, * cSf, * cSb;

#define aff1 0
#define affmax YMAX

#endif	/* ndef CURSES */


#define dont_debug_terminfo

#define fkeymap_terminfo_len 155
struct fkeyentry fkeymap_terminfo [fkeymap_terminfo_len + 1] = {
	{NIL_PTR}
};
static int fkeymap_terminfo_i = 0;

static
void
add_keymap_entry (cap, f, shift_state)
  char * cap;
  voidfunc f;
  unsigned char shift_state;
{
  if (fkeymap_terminfo_i < fkeymap_terminfo_len) {
	fkeymap_terminfo [fkeymap_terminfo_i].fk = cap;
	fkeymap_terminfo [fkeymap_terminfo_i].fp = f;
	fkeymap_terminfo [fkeymap_terminfo_i].fkeyshift = shift_state;
	fkeymap_terminfo_i ++;
	fkeymap_terminfo [fkeymap_terminfo_i].fk = NIL_PTR;
  }
}


static
char *
add_terminfo_entry (tc, ti, f, shift_state)
  char * tc;
  char * ti;
  voidfunc f;
  unsigned char shift_state;
{
  if (f) {
	char * cap = term_getstr (tc, ti);
	if (cap) {
		add_keymap_entry (cap, f, shift_state);
#ifdef debug_terminfo
		printf ("termcap %s / terminfo %s : <^[%s> [shift %X]\n", tc, ti, cap + 1, shift_state);
#endif
		return cap;
	}
  }
  return 0;
}

static
void
add_terminfo_entries ()
{
  char * caphome;
  char * capend;
  caphome = add_terminfo_entry ("K1", "ka1",	HOMEkey, 0);	/* upper left of keypad */
  (void) add_terminfo_entry ("K3", "ka3",	PU, 0);	/* upper right of keypad */
  (void) add_terminfo_entry ("K2", "kb2",	HOP, 0);	/* center of keypad */
  capend = add_terminfo_entry ("K4", "kc1",	ENDkey, 0);	/* lower left of keypad */
  (void) add_terminfo_entry ("K5", "kc3",	PD, 0);	/* lower right of keypad */

  if (caphome && capend) {
    /* if keypad keys are explicitly defined, use them to assign HOME/END;
       if home/begin/home_down/end key definitions refer to different keys, 
       map "small" keypad functions to them;
       if they happen to refer to the same keys, the first setting 
       will have precedence
     */
    (void) add_terminfo_entry ("kh", "khome",	smallHOMEkey, 0);	/* home key */
    (void) add_terminfo_entry ("kH", "kll",	smallENDkey, 0);	/* lower-left key (home down) */
    (void) add_terminfo_entry ("@1", "kbeg",	smallHOMEkey, 0);	/* begin key */
    (void) add_terminfo_entry ("@7", "kend",	smallENDkey, 0);	/* end key */
    (void) add_terminfo_entry ("#2", "kHOM",	HOMEkey, shift_mask);	/* shifted home key */
    (void) add_terminfo_entry ("&9", "kBEG",	HOMEkey, shift_mask);	/* shifted begin key */
    (void) add_terminfo_entry ("*7", "kEND",	ENDkey, shift_mask);	/* shifted end key */
  } else {
    /* if keypad keys are not explicitly defined,
       assign HOME/END to home/begin and home_down/end keys
     */
    (void) add_terminfo_entry ("kh", "khome",	HOMEkey, 0);	/* home key */
    (void) add_terminfo_entry ("kH", "kll",	ENDkey, 0);	/* lower-left key (home down) */
    (void) add_terminfo_entry ("@1", "kbeg",	HOMEkey, 0);	/* begin key */
    (void) add_terminfo_entry ("@7", "kend",	ENDkey, 0);	/* end key */
    (void) add_terminfo_entry ("#2", "kHOM",	smallHOMEkey, shift_mask);	/* shifted home key */
    (void) add_terminfo_entry ("&9", "kBEG",	smallHOMEkey, shift_mask);	/* shifted begin key */
    (void) add_terminfo_entry ("*7", "kEND",	smallENDkey, shift_mask);	/* shifted end key */
  }

  (void) add_terminfo_entry ("kb", "kbs",	DPC, 0);	/* backspace key */
  (void) add_terminfo_entry ("kB", "kcbt",	MPW, 0);	/* back-tab key */
  (void) add_terminfo_entry ("@2", "kcan",	0, 0);	/* cancel key */
  (void) add_terminfo_entry ("ka", "ktbc",	0, 0);	/* clear-all-tabs key */
  (void) add_terminfo_entry ("kC", "kclr",	0, 0);	/* clear-screen or erase key */
  (void) add_terminfo_entry ("@3", "kclo",	0, 0);	/* close key */
  (void) add_terminfo_entry ("@4", "kcmd",	HOP, 0);	/* command key */
  (void) add_terminfo_entry ("@5", "kcpy",	COPY, 0);	/* copy key */
  (void) add_terminfo_entry ("@6", "kcrt",	0, 0);	/* create key */
  (void) add_terminfo_entry ("kt", "kctab",	0, 0);	/* clear-tab key */
  (void) add_terminfo_entry ("kD", "kdch1",	DELkey, 0);	/* delete-character key */
  (void) add_terminfo_entry ("kL", "kdl1",	0, 0);	/* delete-line key */
  (void) add_terminfo_entry ("kd", "kcud1",	MDN, 0);	/* down-arrow key */
  (void) add_terminfo_entry ("kM", "krmir",	0, 0);	/* sent by rmir or smir in insert mode */
  (void) add_terminfo_entry ("@8", "kent",	SNL, 0);	/* enter/send key */
  (void) add_terminfo_entry ("kE", "kel",	0, 0);	/* clear-to-end-of-line key */
  (void) add_terminfo_entry ("kS", "ked",	0, 0);	/* clear-to-end-of-screen key */
  (void) add_terminfo_entry ("@9", "kext",	0, 0);	/* exit key */

  (void) add_terminfo_entry ("k0", "kf0",	F10, 0);	/* F0 function key */
  (void) add_terminfo_entry ("k1", "kf1",	F1, 0);	/* F1 function key */
  (void) add_terminfo_entry ("k2", "kf2",	F2, 0);	/* F2 function key */
  (void) add_terminfo_entry ("k3", "kf3",	F3, 0);	/* F3 function key */
  (void) add_terminfo_entry ("k4", "kf4",	F4, 0);	/* F4 function key */
  (void) add_terminfo_entry ("k5", "kf5",	F5, 0);	/* F5 function key */
  (void) add_terminfo_entry ("k6", "kf6",	F6, 0);	/* F6 function key */
  (void) add_terminfo_entry ("k7", "kf7",	F7, 0);	/* F7 function key */
  (void) add_terminfo_entry ("k8", "kf8",	F8, 0);	/* F8 function key */
  (void) add_terminfo_entry ("k9", "kf9",	F9, 0);	/* F9 function key */
  (void) add_terminfo_entry ("k;", "kf10",	F10, 0);	/* F10 function key */

#ifdef shift_f_keys
	there is no uniform mapping of actual shifted function keys 
	to terminfo F11..F63 names, so better leave these entries out
  (void) add_terminfo_entry ("F1", "kf11",	F11, 0);	/* F11 function key */
  (void) add_terminfo_entry ("F2", "kf12",	F12, 0);	/* F12 function key */
  (void) add_terminfo_entry ("F3", "kf13",	F1, shift_mask);	/* F13 function key */
  (void) add_terminfo_entry ("F4", "kf14",	F2, shift_mask);	/* F14 function key */
  (void) add_terminfo_entry ("F5", "kf15",	F3, shift_mask);	/* F15 function key */
  (void) add_terminfo_entry ("F6", "kf16",	F4, shift_mask);	/* F16 function key */
  (void) add_terminfo_entry ("F7", "kf17",	F5, shift_mask);	/* F17 function key */
  (void) add_terminfo_entry ("F8", "kf18",	F6, shift_mask);	/* F18 function key */
  (void) add_terminfo_entry ("F9", "kf19",	F7, shift_mask);	/* F19 function key */
  (void) add_terminfo_entry ("FA", "kf20",	F8, shift_mask);	/* F20 function key */
  (void) add_terminfo_entry ("FB", "kf21",	F9, shift_mask);	/* F21 function key */
  (void) add_terminfo_entry ("FC", "kf22",	F10, shift_mask);	/* F22 function key */
  (void) add_terminfo_entry ("FD", "kf23",	F11, shift_mask);	/* F23 function key */
  (void) add_terminfo_entry ("FE", "kf24",	F12, shift_mask);	/* F24 function key */
  (void) add_terminfo_entry ("FF", "kf25",	F1, ctrl_mask);	/* F25 function key */
  (void) add_terminfo_entry ("FG", "kf26",	F2, ctrl_mask);	/* F26 function key */
  (void) add_terminfo_entry ("FH", "kf27",	F3, ctrl_mask);	/* F27 function key */
  (void) add_terminfo_entry ("FI", "kf28",	F4, ctrl_mask);	/* F28 function key */
  (void) add_terminfo_entry ("FJ", "kf29",	F5, ctrl_mask);	/* F29 function key */
  (void) add_terminfo_entry ("FK", "kf30",	F6, ctrl_mask);	/* F30 function key */
  (void) add_terminfo_entry ("FL", "kf31",	F7, ctrl_mask);	/* F31 function key */
  (void) add_terminfo_entry ("FM", "kf32",	F8, ctrl_mask);	/* F32 function key */
  (void) add_terminfo_entry ("FN", "kf33",	F9, ctrl_mask);	/* F33 function key */
  (void) add_terminfo_entry ("FO", "kf34",	F10, ctrl_mask);	/* F34 function key */
  (void) add_terminfo_entry ("FP", "kf35",	F11, ctrl_mask);	/* F35 function key */
  (void) add_terminfo_entry ("FQ", "kf36",	F12, ctrl_mask);	/* F36 function key */
  (void) add_terminfo_entry ("FR", "kf37",	F1, ctrlshift_mask);	/* F37 function key */
  (void) add_terminfo_entry ("FS", "kf38",	F2, ctrlshift_mask);	/* F38 function key */
  (void) add_terminfo_entry ("FT", "kf39",	F3, ctrlshift_mask);	/* F39 function key */
  (void) add_terminfo_entry ("FU", "kf40",	F4, ctrlshift_mask);	/* F40 function key */
  (void) add_terminfo_entry ("FV", "kf41",	F5, ctrlshift_mask);	/* F41 function key */
  (void) add_terminfo_entry ("FW", "kf42",	F6, ctrlshift_mask);	/* F42 function key */
  (void) add_terminfo_entry ("FX", "kf43",	F7, ctrlshift_mask);	/* F43 function key */
  (void) add_terminfo_entry ("FY", "kf44",	F8, ctrlshift_mask);	/* F44 function key */
  (void) add_terminfo_entry ("FZ", "kf45",	F9, ctrlshift_mask);	/* F45 function key */
  (void) add_terminfo_entry ("Fa", "kf46",	F10, ctrlshift_mask);	/* F46 function key */
  (void) add_terminfo_entry ("Fb", "kf47",	F11, ctrlshift_mask);	/* F47 function key */
  (void) add_terminfo_entry ("Fc", "kf48",	F12, ctrlshift_mask);	/* F48 function key */
  (void) add_terminfo_entry ("Fd", "kf49",	F1, alt_mask);	/* F49 function key */
  (void) add_terminfo_entry ("Fe", "kf50",	F2, alt_mask);	/* F50 function key */
  (void) add_terminfo_entry ("Ff", "kf51",	F3, alt_mask);	/* F51 function key */
  (void) add_terminfo_entry ("Fg", "kf52",	F4, alt_mask);	/* F52 function key */
  (void) add_terminfo_entry ("Fh", "kf53",	F5, alt_mask);	/* F53 function key */
  (void) add_terminfo_entry ("Fi", "kf54",	F6, alt_mask);	/* F54 function key */
  (void) add_terminfo_entry ("Fj", "kf55",	F7, alt_mask);	/* F55 function key */
  (void) add_terminfo_entry ("Fk", "kf56",	F8, alt_mask);	/* F56 function key */
  (void) add_terminfo_entry ("Fl", "kf57",	F9, alt_mask);	/* F57 function key */
  (void) add_terminfo_entry ("Fm", "kf58",	F10, alt_mask);	/* F58 function key */
  (void) add_terminfo_entry ("Fn", "kf59",	F11, alt_mask);	/* F59 function key */
  (void) add_terminfo_entry ("Fo", "kf60",	F12, alt_mask);	/* F60 function key */
  (void) add_terminfo_entry ("Fp", "kf61",	F1, altshift_mask);	/* F61 function key */
  (void) add_terminfo_entry ("Fq", "kf62",	F2, altshift_mask);	/* F62 function key */
  (void) add_terminfo_entry ("Fr", "kf63",	F3, altshift_mask);	/* F63 function key */
#endif

  (void) add_terminfo_entry ("@0", "kfnd",	FIND, 0);	/* find key */
  (void) add_terminfo_entry ("%1", "khlp",	HELP, 0);	/* help key */
  (void) add_terminfo_entry ("kI", "kich1",	INSkey, 0);	/* insert-character key */
  (void) add_terminfo_entry ("kA", "kil1",	0, 0);	/* insert-line key */
  (void) add_terminfo_entry ("kl", "kcub1",	MLF, 0);	/* left-arrow key */
  (void) add_terminfo_entry ("%2", "kmrk",	MARK, 0);	/* mark key */
  (void) add_terminfo_entry ("%3", "kmsg",	0, 0);	/* message key */
  (void) add_terminfo_entry ("%4", "kmov",	0, 0);	/* move key */
  (void) add_terminfo_entry ("%5", "knxt",	0, 0);	/* next key */
  (void) add_terminfo_entry ("kN", "knp",	PD, 0);	/* next-page key */
  (void) add_terminfo_entry ("%6", "kopn",	EDIT, 0);	/* open key */
  (void) add_terminfo_entry ("%7", "kopt",	QUICKMENU, 0);	/* options key */
  (void) add_terminfo_entry ("kP", "kpp",	PU, 0);	/* previous-page key */
  (void) add_terminfo_entry ("%8", "kprv",	0, 0);	/* previous key */
  (void) add_terminfo_entry ("%9", "kprt",	PRINT, 0);	/* print key */
  (void) add_terminfo_entry ("%0", "krdo",	COPY, 0);	/* redo key */
  (void) add_terminfo_entry ("&1", "kref",	0, 0);	/* reference key */
  (void) add_terminfo_entry ("&2", "krfr",	0, 0);	/* refresh key */
  (void) add_terminfo_entry ("&3", "krpl",	GR, 0);	/* replace key */
  (void) add_terminfo_entry ("&4", "krst",	0, 0);	/* restart key */
  (void) add_terminfo_entry ("&5", "kres",	AGAIN, 0);	/* resume key */
  (void) add_terminfo_entry ("kr", "kcuf1",	MRT, 0);	/* right-arrow key */
  (void) add_terminfo_entry ("&6", "ksav",	WT, 0);	/* save key */
  (void) add_terminfo_entry ("&0", "kCAN",	0, shift_mask);	/* shifted cancel key */
  (void) add_terminfo_entry ("*1", "kCMD",	HOP, shift_mask);	/* shifted command key */
  (void) add_terminfo_entry ("*2", "kCPY",	COPY, shift_mask);	/* shifted copy key */
  (void) add_terminfo_entry ("*3", "kCRT",	0, shift_mask);	/* shifted create key */
  (void) add_terminfo_entry ("*4", "kDC",	DELkey, shift_mask);	/* shifted delete-character key */
  (void) add_terminfo_entry ("*5", "kDL",	0, shift_mask);	/* shifted delete-line key */
  (void) add_terminfo_entry ("*6", "kslt",	MARK, 0);	/* select key */
  (void) add_terminfo_entry ("*8", "kEOL",	0, shift_mask);	/* shifted clear-to-end-of-line key */
  (void) add_terminfo_entry ("*9", "kEXT",	0, shift_mask);	/* shifted exit key */
  (void) add_terminfo_entry ("kF", "kind",	SD, 0);	/* scroll-forward key */
  (void) add_terminfo_entry ("*0", "kFND",	FIND, shift_mask);	/* shifted find key */
  (void) add_terminfo_entry ("#1", "kHLP",	HELP, shift_mask);	/* shifted help key */
  (void) add_terminfo_entry ("#3", "kIC",	INSkey, shift_mask);	/* shifted insert-character key */
  (void) add_terminfo_entry ("#4", "kLFT",	MLF, shift_mask);	/* shifted left-arrow key */
  (void) add_terminfo_entry ("%a", "kMSG",	0, shift_mask);	/* shifted message key */
  (void) add_terminfo_entry ("%b", "kMOV",	0, shift_mask);	/* shifted move key */
  (void) add_terminfo_entry ("%c", "kNXT",	PD, shift_mask);	/* shifted next key */
  (void) add_terminfo_entry ("%d", "kOPT",	handleFlagmenus, shift_mask);	/* shifted options key */
  (void) add_terminfo_entry ("%e", "kPRV",	PU, shift_mask);	/* shifted previous key */
  (void) add_terminfo_entry ("%f", "kPRT",	PRINT, shift_mask);	/* shifted print key */
  (void) add_terminfo_entry ("kR", "kri",	SU, 0);	/* scroll-backward key */
  (void) add_terminfo_entry ("%g", "kRDO",	COPY, shift_mask);	/* shifted redo key */
  (void) add_terminfo_entry ("%h", "kRPL",	REPL, shift_mask);	/* shifted replace key */
  (void) add_terminfo_entry ("%i", "kRIT",	MRT, shift_mask);	/* shifted right-arrow key */
  (void) add_terminfo_entry ("%j", "kRES",	AGAIN, shift_mask);	/* shifted resume key */
  (void) add_terminfo_entry ("!1", "kSAV",	WTU, shift_mask);	/* shifted save key */
  (void) add_terminfo_entry ("!2", "kSPD",	SUSP, shift_mask);	/* shifted suspend key */
  (void) add_terminfo_entry ("kT", "khts",	0, 0);	/* set-tab key */
  (void) add_terminfo_entry ("!3", "kUND",	UNDO, shift_mask);	/* shifted undo key */
  (void) add_terminfo_entry ("&7", "kspd",	SUSP, 0);	/* suspend key */
  (void) add_terminfo_entry ("&8", "kund",	UNDO, 0);	/* undo key */
  (void) add_terminfo_entry ("ku", "kcuu1",	MUP, 0);	/* up-arrow key */
  (void) add_terminfo_entry ("Km", "kmous",	DIRECTxterm, 0);	/* Mouse event has occurred */
}

#endif	/* unix */


/*======================================================================*\
|*			Terminal mode switcher				*|
\*======================================================================*/

static void start_screen_mode _((int kb));
static void end_screen_mode _((void));
static void setup_terminal _((void));
static void reset_terminal _((void));

#ifdef CURSES

#define use_newterm	/* otherwise, redirection to stdout doesn't work */

#ifdef __EMX__		/* __PDCURSES__ ? */
#undef use_newterm
#endif
#ifdef msdos
#undef use_newterm
#endif

static FLAG screen_acquired = False;
static void configure_screen _((void));
# ifdef use_newterm
static SCREEN * myscreen;
extern FILE * fdopen ();
# endif

#endif

#ifdef TERMIO
static FLAG old_termprops_not_saved = True;
#endif
#ifdef SGTTY
static FLAG old_termprops_not_saved = True;
#endif

static FLAG init_done = False;

/* the termios ISIG flag suppresses signal generation on 
   tty input of INTR, QUIT, SUSP, or DSUSP associated keys */
#define dont_use_ISIG


/*
 * Set (True) or Restore (False) tty raw mode.
 * Also set signal characters (except for ^\) to UNDEF. ^\ is caught.
 */
void
raw_mode (to_raw_state)
  FLAG to_raw_state;
{
#ifdef TERMIO
  static struct termios old_termio;
	 struct termios new_termio;
#ifdef TCGETS
# define gettermio(fd, iopoi)	(void) ioctl (fd, TCGETS, iopoi);
# ifdef TCSETSW
# define settermio(fd, iopoi)	(void) ioctl (fd, TCSETSW, iopoi);
# else
# define settermio(fd, iopoi)	(void) ioctl (fd, TCSETS, iopoi);
# endif
#else
# define gettermio(fd, iopoi)	tcgetattr (fd, iopoi);
# ifdef TCSADRAIN
# define settermio(fd, iopoi)	tcsetattr (fd, TCSADRAIN, iopoi);
# else
# define settermio(fd, iopoi)	tcsetattr (fd, 0, iopoi);
# endif
#endif
#endif /* TERMIO */

#ifdef SGTTY
  static struct sgttyb old_tty;
	 struct sgttyb new_tty;
  static int oldlmode;
	 int lmode;
  static struct tchars old_tchars;
  static struct ltchars old_ltchars;
#define NDEF '\377'
  static struct tchars new_tchars = {NDEF, quit_char, NDEF, NDEF, NDEF, NDEF};
  static struct tchars new_QStchars = {NDEF, quit_char, '\021', '\023', NDEF, NDEF};
  static struct ltchars new_ltchars = {NDEF, NDEF, NDEF, NDEF, NDEF, NDEF};
/* correspondence between the tchars/ltchars characters of the sgtty 
   interface and the c_cc characters of the termios interface (codes vary):
	sgtty		termio		sgtty		termio
	t_intrc		VINTR		t_suspc		VSUSP
	t_quitc		VQUIT		t_dsuspc	VDSUSP
	t_startc	VSTART		t_rprntc	VREPRINT
	t_stopc		VSTOP		t_flushc	VDISCARD
	t_eofc		VEOF (VMIN)	t_werasc	VWERASE
	t_brkc		VEOL (VTIME)	t_lnextc	VLNEXT
*/
#endif /* SGTTY */


  if (to_raw_state == False) {
	isscreenmode = False;

/* Reset screen */

	reset_terminal ();
	end_screen_mode ();

#ifndef CURSES
	flush ();
#endif


/* Reset tty */
#ifdef CURSES
	savetty ();
	endwin ();
# ifdef vms
	(void) system ("set terminal /ttsync /nopasthru");
# endif
#endif
#ifdef TERMIO
	settermio (input_fd, & old_termio);
/*	one byte of output swallowed here on SunOS	*/
#endif
#ifdef SGTTY
	(void) ioctl (input_fd, TIOCSETP, & old_tty);
	(void) ioctl (input_fd, TIOCSETC, & old_tchars);
/*	one byte of output swallowed here on SunOS	*/
	(void) ioctl (input_fd, TIOCSLTC, & old_ltchars);
	(void) ioctl (input_fd, TIOCLSET, & oldlmode);
#endif
/*	output a byte that SunOS may swallow:	*/
	(void) write (output_fd, " \r", 2);
	return;
  }


  else /* (to_raw_state == True) */ {
	if (isscreenmode) {
		/* first terminal mode initialization is delayed 
		   and de-coupled from tty configuration */
		start_screen_mode (1);
		setup_terminal ();
		init_done = True;
		return;
	}

	isscreenmode = True;

/* Init tty */
#ifdef CURSES

# ifdef vms
	(void) system ("set terminal /pasthru /nottsync");
# endif

	if (screen_acquired == False) {
# ifdef use_newterm
		FILE * ttyin = fdopen (input_fd, "r");
		FILE * ttyout = fdopen (output_fd, "w");
		myscreen = newterm (NIL_PTR, ttyout, ttyin);
# else
		initscr ();
# endif

		add_terminfo_entries ();

		screen_acquired = True;
		configure_screen ();
	} else {
		resetty ();
	}

	getwinsize ();
#endif
#ifdef TERMIO
	if (old_termprops_not_saved) {
		/* Save old tty settings */
		gettermio (input_fd, & old_termio);

		/* Determine configured erase character */
		erase_char = old_termio.c_cc [VERASE];
		/*kill_char = old_termio.c_cc [VKILL];*/

		old_termprops_not_saved = False;
	}

	gettermio (input_fd, & new_termio);

	if (controlQS == False) {
		new_termio.c_iflag &= ~(ISTRIP|IXON|IXOFF);
	} else {
		new_termio.c_iflag &= ~(ISTRIP);
	}
	new_termio.c_oflag &= ~OPOST;
	new_termio.c_cflag &= ~(PARENB|CSIZE);
	new_termio.c_cflag |= CS8;
	new_termio.c_lflag &= ~(ICANON|ECHO
#ifdef use_ISIG
#ifdef ISIG
		|ISIG
#endif
#endif
		);
	new_termio.c_iflag &= ~ICRNL;	/* pass through ^M */
#define NDEF '\000'
	new_termio.c_cc [VMIN] = 1;
	new_termio.c_cc [VTIME] = 0;
	new_termio.c_cc [VQUIT] = quit_char;	/* don't use ISIG! */
	new_termio.c_cc [VINTR] = NDEF;
	new_termio.c_cc [VSUSP] = NDEF;
#ifdef VSTOP
	new_termio.c_cc [VSTOP] = NDEF;	/* or/also use IXOFF? */
#endif
#ifdef VDISCARD
	new_termio.c_cc [VDISCARD] = NDEF;
#endif
#ifdef VDSUSP
	new_termio.c_cc [VDSUSP] = NDEF;
#endif
#ifdef VLNEXT
	new_termio.c_cc [VLNEXT] = NDEF;
#endif
	settermio (input_fd, & new_termio);
#endif /* TERMIO */
#ifdef SGTTY
	if (old_termprops_not_saved) {
		/* Save old tty settings */
		(void) ioctl (input_fd, TIOCGETP, & old_tty);
		(void) ioctl (input_fd, TIOCGETC, & old_tchars);
		(void) ioctl (input_fd, TIOCGLTC, & old_ltchars);
		(void) ioctl (input_fd, TIOCLGET, & oldlmode);

		/* Determine configured erase character */
		erase_char = old_tty.sg_erase;
		/*kill_char = old_tty.sg_kill;*/

		old_termprops_not_saved = False;
	}

	/* Set line mode */
	/* If this feature should not be available on some system, 
	   RAW must be used instead of CBREAK below to enable 8 bit output */
	lmode = oldlmode;
	lmode |= LPASS8; /* enable 8 bit characters on input in CBREAK mode */
	lmode |= LLITOUT; /* enable 8 bit characters on output in CBREAK mode;
	    this may not be necessary in newer Unixes, e.g. SunOS 4;
	    output handling is slightly complicated by LITOUT */
	(void) ioctl (input_fd, TIOCLSET, & lmode);
	/* Set tty to CBREAK (or RAW) mode */
	new_tty = old_tty;
	new_tty.sg_flags &= ~ECHO;
	new_tty.sg_flags |= CBREAK;
	(void) ioctl (input_fd, TIOCSETP, & new_tty);
	/* Unset signal chars */
	if (controlQS == False) {
		(void) ioctl (input_fd, TIOCSETC, & new_tchars);  /* Only leaves quit_char */
	} else {
		(void) ioctl (input_fd, TIOCSETC, & new_QStchars);  /* Leaves quit_char, ^Q, ^S */
	}
	(void) ioctl (input_fd, TIOCSLTC, & new_ltchars); /* Leaves nothing */
#endif /* SGTTY */


/* Init screen */
	if (init_done) { /* postpone on first invocation of raw_mode */
		/* keyboard modes */
		start_screen_mode (1);
		/* specific terminal modes */
		setup_terminal ();
	}
	/* do not postpone actual screen mode */
	start_screen_mode (0);

#ifdef CURSES
	refresh ();
	/* Determine configured erase character */
	erase_char = erasechar ();
	/*kill_char = killchar ();*/
#else
	flush ();
#endif

/* Setup signal handlers */
#ifdef SIGQUIT
	signal (SIGQUIT, catchquit);	/* Catch quit_char */
#endif
#ifdef SIGBREAK
	signal (SIGBREAK, catchbreak);	/* control-Break (OS/2) */
#else
# ifdef msdos_suppressbreak
	ctrlbrk (controlbreak);	/* completely useless, stupid Turbo-C! */
# endif
#endif
#ifdef SIGINT
	signal (SIGINT, catchint);	/* Catch INTR char (^C) */
#endif
#ifdef SIGWINCH
	signal (SIGWINCH, catchwinch);	/* Catch window size changes */
#endif
  }
}


/*======================================================================*\
|*			Terminal mode setup				*|
\*======================================================================*/

#ifdef unix

char restore_ansi7 [27];
FLAG do_restore_ansi7 = False;

static void
setup_terminal ()
{
/* set special keyboard modes */
  if (use_modifyOtherKeys) {
	putescape ("\033[>4;2m");
  }

/* specific terminal configuration */
  if (configure_xterm_keyboard && xterm_version > 0) {
	putescape ("\033[?1037s"); /* Save DEC mode value */
	putescape ("\033[?1037h"); /* Send DEL from the editing‐keypad Delete key */
	putescape ("\033[?1036s"); /* Save DEC mode value */
	putescape ("\033[?1036h"); /* Send ESC when Meta modifies a key (metaSendsEscape) */
  }
}

static void
reset_terminal ()
{
  /* restore ANSI color 7 (redefined for dim mode) */
  if (do_restore_ansi7) {
	putescape (restore_ansi7);
  }

  /* reset special keyboard modes */
  if (use_modifyOtherKeys) {
#ifdef reset_modifyOtherKeys
	if (mintty_version == 400) {
		putescape ("\033[>4;0m");
	} else {
		putescape ("\033[>4m");
	}
#else
	putescape ("\033[>4m");
#endif
  }

  /* try to restore specific terminal modes */
  if (configure_xterm_keyboard && xterm_version > 0) {
	putescape ("\033[?1037r"); /* Restore DEC mode value */
	putescape ("\033[?1036r"); /* Restore DEC mode value */
  }
}

#else

static void
setup_terminal ()
{
}

static void
reset_terminal ()
{
}

#endif


/*======================================================================*\
|*			Escape code I/O routine				*|
\*======================================================================*/

void
putescape (s)
  char * s;
{
#ifdef CURSES
	/* synchronize with buffered screen output */
	flush ();
	/* bypass curses for escape sequence */
	if (write (output_fd, s, strlen (s)) <= 0) {
		/* terminal write error; cannot do anything */
	}
#else
	putstring (s);
#endif
}


/*======================================================================*\
|*			Menu borders					*|
\*======================================================================*/

/*	block graphics mapping
	note: VGA (PC) encoding also used on Linux console!
VT100	VGA	curses
j	D9	ACS_LRCORNER
k	BF	ACS_URCORNER
l	DA	ACS_ULCORNER
m	C0	ACS_LLCORNER
n		ACS_PLUS
o		ACS_S1
p		ACS_S3
q	C4	ACS_HLINE
r		ACS_S7
s		ACS_S9
t	C3	ACS_LTEE
u	B4	ACS_RTEE
v	C1	ACS_BTEE
w	C2	ACS_TTEE
x	B3	ACS_VLINE
*/

/**
   ASCII block graphics mapping
   +-+-+
   +-+-+
   | | |
   +-+-+
 */
static
char *
asciiblockchar (c)
  character c;
{
    if (menu_border_style == 'r') {
	switch (c) {
		case 'j':	return "/";	/* LR */
		case 'k':	return "\\";	/* UR */
		case 'l':	return "/";	/* UL */
		case 'm':	return "\\";	/* LL */
		case 'n':	return "+";	/* crossing (not used) */
		case 'q':	if (cjk_width_data_version) {
					return "--";	/* hor. line */
				} else {
					return "-";	/* hor. line */
				}
		case 't':	return "+";	/* left tee */
		case 'u':	return "+";	/* right tee */
		case 'v':	return "+";	/* bottom tee */
		case 'w':	return "+";	/* top tee */
		case 'x':	return "|";	/* vert. line */
		case 'f':
		case 'g':	/* scrolling indication */
				if (utf8_screen) {
					return "¦";
				} else if (cjk_term || mapped_term) {
					return "|";
				} else {
					return "�";
				}
		default: return "";
	}
    } else {
	switch (c) {
		case 'j':	return "+";	/* LR */
		case 'k':	return "+";	/* UR */
		case 'l':	return "+";	/* UL */
		case 'm':	return "+";	/* LL */
		case 'n':	return "+";	/* crossing (not used) */
		case 'q':	if (cjk_width_data_version) {
					return "--";	/* hor. line */
				} else {
					return "-";	/* hor. line */
				}
		case 't':	return "+";	/* left tee */
		case 'u':	return "+";	/* right tee */
		case 'v':	return "+";	/* bottom tee */
		case 'w':	return "+";	/* top tee */
		case 'x':	return "|";	/* vert. line */
		case 'f':
		case 'g':	/* scrolling indication */
				if (utf8_screen) {
					return "¦";
				} else if (cjk_term || mapped_term) {
					return "|";
				} else {
					return "�";
				}
		default: return "";
	}
    }
}

#ifndef CURSES

/**
   VGA (PC/DOS) block graphics mapping
 */
static
character
vgablockchar (c)
  character c;
{
  switch (c) {
	case 'j':	return 0xD9;	/* LR */
	case 'k':	return 0xBF;	/* UR */
	case 'l':	return 0xDA;	/* UL */
	case 'm':	return 0xC0;	/* LL */
	case 'n':	return 0xC5;	/* crossing (not used) */
	case 'q':	return 0xC4;	/* hor. line */
	case 't':	return 0xC3;	/* left tee */
	case 'u':	return 0xB4;	/* right tee */
	case 'v':	return 0xC1;	/* bottom tee */
	case 'w':	return 0xC2;	/* top tee */
	case 'x':	return 0xB3;	/* vert. line */
	case 'f':
	case 'g':	return 0xB2;	/* box as scrolling indication */
	default:	return c;
  }
}

#ifndef msdos

/**
   block graphics mapping using termcap "ac" / terminfo "acsc" capability, 
   or VT100 block graphics by default
 */
static
char *
acblockchar (c)
  character c;
{
  character cout = '\0';
  static char sout [3];
  char * spoi = sout;

  if (c == 'f' || c == 'g') {
#ifdef choose_one_of
	c = '`';
	c = 'a';
	c = '|';
	c = 'f';
#endif
	c = '`';
  }

  if (* cAC) {
	int i;
	for (i = 0; i < strlen (cAC); i += 2) {
		if (cAC [i] == c) {
			cout = cAC [i + 1];
			break;
		}
	}
	if (cout == '\0') {
		return asciiblockchar (c);
	}
  } else {
	cout = c;
  }

  * spoi ++ = cout;
  if (c == 'q' && cjk_width_data_version && cjk_term) {
	* spoi ++ = cout;
  }
  * spoi = '\0';
  return sout;
}

#endif

#endif

/**
   Unicode block graphics mapping
   ┌─┬─┐  ╭─┬─╮
   ├─┼─┤  ├─┼─┤
   │ │ │  │ │ │
   └─┴─┘  ╰─┴─╯
   ┏━┳━┓  ╔═╦═╗
   ┣━╋━┫  ╠═╬═╣
   ┃ ┃ ┃  ║ ║ ║
   ┗━┻━┛  ╚═╩═╝
 */
static
char *
unicodeblockchar (c)
  character c;
{
  if (use_ascii_graphics) {
	return asciiblockchar (c);
  } else {
    if (menu_border_style == 'f') {
	switch (c) {
		case 'j':	return "┛";	/* LR */
		case 'k':	return "┓";	/* UR */
		case 'l':	return "┏";	/* UL */
		case 'm':	return "┗";	/* LL */
		case 'n':	return "╋";	/* crossing (not used) */
		case 'q':	return "━";	/* hor. line */
		case 't':	return "┣";	/* left tee */
		case 'u':	return "┫";	/* right tee */
		case 'v':	return "┻";	/* bottom tee */
		case 'w':	return "┳";	/* top tee */
		case 'x':	return "┃";	/* vert. line */
		case 'f':
		case 'g':	return "┇";	/* scrolling indication */
		default: return "";
	}
    } else if (menu_border_style == 'd') {
	switch (c) {
		case 'j':	return "╝";	/* LR */
		case 'k':	return "╗";	/* UR */
		case 'l':	return "╔";	/* UL */
		case 'm':	return "╚";	/* LL */
		case 'n':	return "╬";	/* crossing (not used) */
		case 'q':	return "═";	/* hor. line */
		case 't':	return "╠";	/* left tee */
		case 'u':	return "╣";	/* right tee */
		case 'v':	return "╩";	/* bottom tee */
		case 'w':	return "╦";	/* top tee */
		case 'x':	return "║";	/* vert. line */
		case 'f':
		case 'g':	return "║";	/* scrolling indication */
		default: return "";
	}
    } else if (menu_border_style == 'r') {
	switch (c) {
		case 'j':	return "╯";	/* LR */
		case 'k':	return "╮";	/* UR */
		case 'l':	return "╭";	/* UL */
		case 'm':	return "╰";	/* LL */
		case 'n':	return "┼";	/* crossing (not used) */
		case 'q':	return "─";	/* hor. line */
		case 't':	return "├";	/* left tee */
		case 'u':	return "┤";	/* right tee */
		case 'v':	return "┴";	/* bottom tee */
		case 'w':	return "┬";	/* top tee */
		case 'x':	return "│";	/* vert. line */
		case 'f':
		case 'g':	return "┆";	/* scrolling indication */
		default: return "";
	}
    } else {
	switch (c) {
		case 'j':	return "┘";	/* LR */
		case 'k':	return "┐";	/* UR */
		case 'l':	return "┌";	/* UL */
		case 'm':	return "└";	/* LL */
		case 'n':	return "┼";	/* crossing (not used) */
		case 'q':	return "─";	/* hor. line */
		case 't':	return "├";	/* left tee */
		case 'u':	return "┤";	/* right tee */
		case 'v':	return "┴";	/* bottom tee */
		case 'w':	return "┬";	/* top tee */
		case 'x':	return "│";	/* vert. line */
		case 'f':
		case 'g':	return "┆";	/* scrolling indication */
		default: return "";
	}
    }
  }
}


/*======================================================================*\
|*			Mouse mode control				*|
\*======================================================================*/

#ifdef unix

/**
   Enable/disable xterm button event reporting mode.
 */
void
mouse_button_event_mode (report)
  FLAG report;
{
  if (! use_mouse_button_event_tracking) {
	return;
  }

#ifdef debug_mouse
  printf ("mouse_button_event_mode %d\n", report);
#endif

  if (report) {
	/* activate button-event tracking */
	putescape (cMouseEventBtnOn);
	is_mouse_button_event_mode_enabled = True;
  } else if (is_mouse_button_event_mode_enabled) {
	/* do not deactivate button-event tracking */
	/* -- putescape (cMouseEventBtnOff); -- */
	/* reenable mouse highlight tracking mode */
	mouse_hilite_mode (True);
	flush ();
	is_mouse_button_event_mode_enabled = False;
  }
}

/**
   Enable/disable xterm mouse tracking (and highlighting) mode.
 */
void
mouse_hilite_mode (hilite)
  FLAG hilite;
{
  if (! use_mouse_hilite_tracking) {
	return;
  }

#ifdef debug_mouse
  printf ("mouse_hilite_mode %d\n", hilite);
#endif

  if (hilite) {
# ifdef debug_hilite_tracking
	printf ("enabling hilite tracking\n");
# endif
	putescape (cMouseHighlightOn);
	is_mouse_hilite_mode_enabled = True;
  } else {
# ifdef debug_hilite_tracking
	printf ("disabling hilite tracking\n");
# endif
	putescape (cMouseHighlightOff);
	is_mouse_hilite_mode_enabled = False;

	/* restore other modes */
	putescape (cMouseX10On);	/* activate mouse reporting */
	putescape (cMouseButtonOn);
	putescape (cMouseEventBtnOn);
	putescape (cMouseFocusOn);	/* activate focus reports */
	putescape (cMouseAmbigOn);	/* activate ambiguous width change reports */
  }
}

/**
   Switch on or off actual xterm mouse hilite tracking.
 */
void
mouse_hilite_tracking_on (startx, starty, firstrow, lastrow)
  int startx;
  int starty;
  int firstrow;
  int lastrow;
{
  char track [22];

  if (! use_mouse_hilite_tracking) {
	return;
  }

#ifdef debug_mouse
  printf ("start mouse hilite tracking\n");
#endif

  build_string (track, "\033[1;%d;%d;%d;%dT", 
			startx, starty, firstrow, lastrow);
# ifdef debug_hilite_tracking
  printf ("initiating hilite tracking\n");
# endif
  putescape (track);
  flush ();
}

void
mouse_hilite_tracking_off ()
{
  if (! use_mouse_hilite_tracking) {
	return;
  }

#ifdef debug_mouse
  printf ("stop mouse hilite tracking\n");
#endif

# ifdef debug_hilite_tracking
  printf ("aborting hilite tracking\n");
# endif
  putescape ("\033[0;0;0;0;0T");
  flush ();
}

/**
   Adapt mouse mode to menu state (menu opened?)
   While a menu is open, mouse movement should be reported separately.
 */
void
menu_mouse_mode (menu)
  FLAG menu;
{
  if (! use_mouse) {
	return;
  }

#ifdef debug_mouse
  printf ("menu_mouse_mode %d\n", menu);
#endif

  if (menu) {
	if (in_menu_mouse_mode == False) {
		if (use_mouse_hilite_tracking) {
#ifndef dynamic_hilite_tracking
			/* deactivate hilite tracking */
			mouse_hilite_mode (False);
#endif
		}
		if (use_mouse_button_event_tracking) {
			/* activate button-event tracking */
			putescape (cMouseEventBtnOn);
			if (use_mouse_anymove_inmenu) {
				/* activate any-event tracking */
				putescape (cMouseEventAnyOn);
			}
		}
		/* hide cursor for menu display if reverse mode available 
		   for menu item marking
		 */
		if (can_reverse_mode) {
			disp_cursor (False);
		}
	}
  } else {
	if (in_menu_mouse_mode) {
		if (use_mouse_button_event_tracking) {
			if (use_mouse_anymove_inmenu && ! use_mouse_anymove_always) {
				/* deactivate any-event tracking */
				putescape (cMouseEventAnyOff);
			}
			/* reactivate button-event tracking */
			putescape (cMouseEventBtnOn);
			if (use_mouse_anymove_always) {
				/* upgrade to any-event tracking */
				putescape (cMouseEventAnyOn);
			}
		}
		if (use_mouse_hilite_tracking) {
#ifndef dynamic_hilite_tracking
			/* activate hilite tracking */
			mouse_hilite_mode (True);
#endif
		}
		/* turn cursor visible again; 
		   (was turned invisible only if reverse mode available)
		 */
		if (can_reverse_mode) {
			disp_cursor (True);
		}
	}
  }
  in_menu_mouse_mode = menu;
}

#endif


#ifdef CURSES

/*======================================================================*\
	curses
\*======================================================================*/


#define TRUE (char) 1
#define FALSE (char) 0
static void init_colours _((void));
extern int curs_readchar _((void));


void
__putchar (c)
  register character c;
{
  addch (c);
}

#ifdef __PDCURSES__
#if defined(DOS) || defined(OS2) || defined(WIN32)

#ifndef ACS_S3
#define ACS_S3 0
#endif
#ifndef ACS_S7
#define ACS_S7 0
#endif
#ifndef ACS_LEQUAL
#define ACS_LEQUAL 0
#endif
#ifndef ACS_GEQUAL
#define ACS_GEQUAL 0
#endif
#ifndef ACS_NEQUAL
#define ACS_NEQUAL 0
#endif
#ifndef ACS_PI
#define ACS_PI 0
#endif
#ifndef ACS_STERLING
#define ACS_STERLING 0
#endif

chtype acs_map [] = {
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, 
/* 20 */
0, 0, 0, 0, 0, 0, 0, ACS_DIAMOND, 
0, 0, 0, ACS_RARROW, ACS_LARROW, ACS_UARROW, ACS_DARROW, 0, 
/* 30 */
ACS_BLOCK, 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, 
/* 60 */
0, ACS_CKBOARD, 0, 0, 0, 0, ACS_DEGREE, ACS_PLMINUS, 
ACS_BOARD, ACS_LANTERN, ACS_LRCORNER, ACS_URCORNER, 
ACS_ULCORNER, ACS_LLCORNER, ACS_PLUS, ACS_S1, 
/* 70 */
ACS_S3, ACS_HLINE, ACS_S7, ACS_S9, 
ACS_LTEE, ACS_RTEE, ACS_BTEE, ACS_TTEE, 
ACS_VLINE, ACS_LEQUAL, ACS_GEQUAL, ACS_PI, 
ACS_NEQUAL, ACS_STERLING, ACS_BULLET, 0, 
/* 80 */
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, 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
};
#endif	/* if defined(DOS) || defined(OS2) || defined(WIN32) */
#endif	/* ifdef __PDCURSES__ */

#ifdef __CYGWIN__
/* fix error in ncurses.h */
#undef acs_map
extern NCURSES_EXPORT_VAR(chtype) acs_map[];
#endif

void
putblockchar (c)
  register character c;
{
#ifdef __CYGWIN__no_ACS_
	/* acs_map broken with -lncursesw */
  if (use_normalchars_boxdrawing) {
	addstr (unicodeblockchar (c));
  } else {
	addstr (asciiblockchar (c));
  }
#else
  if (use_normalchars_boxdrawing) {
	addstr (unicodeblockchar (c));
  } else if (c == 'f' || c == 'g') {
#ifdef choose_one_of
	addch (ACS_DIAMOND);
	addch (ACS_CKBOARD);
	addch (ACS_NEQUAL);
	addch (ACS_DEGREE);
#endif
	addch (ACS_DIAMOND);
  } else {
#ifdef __CYGWIN__no_acs_map
	switch (c) {
		case 'j':	addch (ACS_LRCORNER);	/* LR */
		case 'k':	addch (ACS_URCORNER);	/* UR */
		case 'l':	addch (ACS_ULCORNER);	/* UL */
		case 'm':	addch (ACS_LLCORNER);	/* LL */
		case 'n':	addch (ACS_PLUS);	/* crossing (not used) */
		case 'q':	addch (ACS_HLINE);	/* hor. line */
		case 't':	addch (ACS_LTEE);	/* left tee */
		case 'u':	addch (ACS_RTEE);	/* right tee */
		case 'v':	addch (ACS_BTEE);	/* bottom tee */
		case 'w':	addch (ACS_TTEE);	/* top tee */
		case 'x':	addch (ACS_VLINE);	/* vert. line */
		default:	addch (' ');
	}
#else
	addch (acs_map [c]);
#endif
  }
#endif
}

void
ring_bell ()
{
  beep ();
}

void
putstring (str)
  register char * str;
{
  addstr (str);
}

void
flush ()
{
  refresh ();
}

void
clear_screen ()
{
  clear ();
}

void
clear_eol ()
{
  clrtoeol ();
}

void
erase_chars (n)
  register int n;
{
  while (n -- > 0) {
	__putchar (' ');
  }
}

void
scroll_forward ()
{
  scroll (stdscr);
}

void
scroll_reverse ()
{ /* only to be called if can_add_line or cursor is at top of screen */
  insertln ();
}

void
add_line (y)
  register int y;
{ /* only to be called if can_add_line == True */
  move (y + MENU, 0);
  insertln ();
}

void
delete_line (y)
  register int y;
{
  move (y + MENU, 0);
  deleteln ();
}

void
set_cursor (x, y)
  register int x;
  register int y;
{
  current_cursor_y = y;
  move (y + MENU, x);
}

void
reverse_on ()
{
  standout ();
}

void
reverse_off ()
{
  standend ();
}


static
void
configure_screen ()
{
#ifdef __PDCURSES__
  keypad (stdscr, TRUE);
#endif

#ifdef KEY_MOUSE

# ifdef __PDCURSES__
  (void) mouse_set (ALL_MOUSE_EVENTS);
# else
#  ifdef NCURSES_VERSION
  (void) mousemask (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED
#   ifdef BUTTON_SHIFT
		    | BUTTON_SHIFT
#   endif
	, /*(mmask_t)*/ (unsigned long) 0);
#  endif
# endif
#endif

  init_colours ();

#define use_cbreak

#ifdef vms
  crmode ();
#else
#ifdef use_cbreak
  /* not sufficient to suppress ^S processing on Unix in pipe ?! */
  /* but now also VSTOP is explicitly removed */
  cbreak ();
#else
  raw ();
#endif
  nonl ();
#endif

  meta (stdscr, TRUE);	/* should force 8-bit-cleanness but doesn't work */
  noecho ();
  scrollok (stdscr, FALSE);

#ifdef unix
# ifndef vax
#  ifndef __EMX__
  idlok (stdscr, TRUE);
#  endif
#  ifndef sun
  typeahead (input_fd);
#  endif
# endif
#endif
}

static
void
start_screen_mode (kb)
  int kb;
{
  /* for curses, see configure_screen () above */
#ifndef dynamic_hilite_tracking
  /* activate hilite tracking */
  mouse_hilite_mode (True);
#endif
}

static
void
end_screen_mode ()
{
#ifndef dynamic_hilite_tracking
  /* activate hilite tracking */
  mouse_hilite_mode (False);
#endif
}


static
void
get_term_cap (TERMname)
  char * TERMname;
{
#ifdef SETLOCALE
  setlocale (LC_ALL, "");
#endif

  YMAX = LINES - 1 - MENU;	/* # of lines */
  XMAX = COLS - 1;	/* # of columns */
/*  getwinsize (); */
}

void
altcset_on ()
{
	attron (A_ALTCHARSET);
}

void
altcset_off ()
{
	attroff (A_ALTCHARSET);
}

void
disp_cursor (visible)
  FLAG visible;
{
	if (visible) {
		curs_set (1);
	} else {
		curs_set (0);
	}
}

void
set_screen_mode (m)
  int m;
{}

void
maximize_restore_screen ()
{
}

static
void
resize_screen (l, c)
  int l;
  int c;
{
  static char s [15];
  build_string (s, "\033[8;%d;%dt", l, c);
  putescape (s);
}

void
resize_the_screen (sb, keep_columns)
  FLAG sb;
  FLAG keep_columns;
{
  int ldif = 6;
  int coldif = 13;
  if (sb == SMALLER) {
	ldif = - ldif;
	coldif = - coldif;
  }
  if (keep_columns) {
	coldif = 0;
  }

  resize_screen (YMAX + 1 + MENU + ldif, XMAX + 1 + coldif);
}

void
switch_textmode_height (cycle)
  FLAG cycle;
{}

#else	/* ifdef CURSES - else: */


/*======================================================================*\
	non-curses
\*======================================================================*/


#ifndef msdos
void
ring_bell ()
{
  putchar ('\07');
}
#endif


/*======================================================================*\
|*			Basic buffered screen output			*|
\*======================================================================*/

/* (long) for the sake of short int Turbo-C */
#define screenbuflen	(((((long) maxXMAX * (long) maxYMAX) >> 10) + 1) << 10)
static char screenbuf [screenbuflen + 1];
static unsigned int screenbuf_count = 0;


/*
 * Flush the screen buffer
 */
static
int
flush_screenbuf ()
{
  if (screenbuf_count <= 0) {		/* There is nothing to flush */
	return FINE;
  }
#ifdef conio
  cputs (screenbuf);
#else
#ifdef BorlandC
  screenbuf [screenbuf_count] = '\0';
/* don't ask me why that crazy compiler doesn't work with write () below */
  printf ("%s", screenbuf);
#else
  {
	char * writepoi = screenbuf;
	int written = 0;
	int none_count = 0;
/*	int less_count = 0;	*/

	while (screenbuf_count > 0) {
		written = write (output_fd, writepoi, screenbuf_count);
		if (written == -1) {
			if (geterrno () == EINTR && winchg) {
				/* try again */
			} else {
				bad_write (output_fd);
				screenbuf_count = 0;
				return ERRORS;
			}
		} else if (written == 0) {
			none_count ++;
			if (none_count > 20) {
				bad_write (output_fd);
				screenbuf_count = 0;
				return ERRORS;
			}
		} else {
			screenbuf_count -= written;
			writepoi += written;
		}
	}
  }
#endif
#endif

  screenbuf_count = 0;
  return FINE;
}

void
flush ()
{
  (void) flush_screenbuf ();
}

/*
 * putoutchar does a buffered output to screen.
 */
static
int
putoutchar (c)
  character c;
{
  char clow;

  if (c == '\n') {
	if (putoutchar ('\r') == ERRORS) {
		return ERRORS;
	}
  }
  if (translate_output) {
	if ((c & '\200') != '\0') {
		altcset_on ();
		clow = (c & '\177');
		if ((int) clow < translen) {
			putoutchar (transout [(int) clow]);
		} else {
			putoutchar (clow);
		}
		altcset_off ();
		return FINE;
	}
  }
  screenbuf [screenbuf_count ++] = c;
  if (screenbuf_count == screenbuflen) {
	return flush_screenbuf ();
  }

#define dont_debug_all_output
#ifdef debug_all_output
  if (c == '\033') {
	printf ("^[");
  } else {
	printf ("%c", c);
  }
#endif
#ifdef debug_flush_output
  flush ();
#endif

  return FINE;
}

/*
 * Putoutstring writes the given string out to the terminal.
 * (buffered via misused screen buffer!)
putstring (str) does putoutstring (str) unless with curses or conio
 */
static
void
putoutstring (text)
  register char * text;
{
  while (* text != '\0') {
	(void) putoutchar (* text ++);
  }
}

void
__putchar (c)
  register character c;
{
#ifdef conio
  putch (c);
#else
  putoutchar (c);
#endif
}

void
putstring (str)
  register char * str;
{
#ifdef conio
  cputs (str);
#else
  putoutstring (str);
#endif
}

/**
   Output a menu border character. Decide which style to use, 
   block graphics (VT100 or VGA), Unicode graphics, ASCII graphics.
   This and it's setup is a mess and could do with some revision.
 */
void
putblockchar (c)
  register character c;
{
#ifdef conio
  if (use_ascii_graphics) {
	putstring (asciiblockchar (c));
  } else {
	putchar (vgablockchar (c));
  }
#else
  if (use_vga_block_graphics) {
	putoutchar (vgablockchar (c));
  } else
	if (use_normalchars_boxdrawing) {
		putoutstring (unicodeblockchar (c));
	} else if (use_pc_block_graphics) {
		putoutchar (vgablockchar (c));
	} else {
		putoutstring (acblockchar (c));
	}
#endif
}


/*======================================================================*\
|*			Screen control functions			*|
\*======================================================================*/

#ifdef unix

void
clear_screen ()
{
  termputstr (cCL, affmax);
}

void
clear_eol ()
{
  if (can_clear_eol) {
	termputstr (cCE, aff1);
  }
}

void
erase_chars (n)
  register int n;
{
  termputstr (tgoto (cEC, 0, n), aff1);
}

void
scroll_forward ()
{
  set_cursor (0, YMAX);
  termputstr ("\n", affmax);
}

void
scroll_reverse ()
{ /* only to be called if can_add_line or cursor is at top of screen */
  if (MENU && can_add_line) {
	add_line (0);
  } else {
	termputstr (cSR, affmax);
  }
}

void
add_line (y)
  register int y;
{ /* only to be called if can_add_line == True */
  if (cAL) {
	set_cursor (0, y);
	termputstr (cAL, affmax);
  } else {
	set_cursor (0, y);
	termputstr (cSC, aff1);
	termputstr (tgoto (cCS, YMAX + MENU, y + MENU), aff1);
	termputstr (cRC, aff1);
	termputstr (cSR, affmax);
	termputstr (tgoto (cCS, YMAX + MENU, 0), aff1);
	termputstr (cRC, aff1);
  }
}

void
delete_line (y)
  register int y;
{
  if (cDL) {
	set_cursor (0, y);
	termputstr (cDL, affmax);
  } else {
	set_cursor (0, y);
	termputstr (cSC, aff1);
	termputstr (tgoto (cCS, YMAX + MENU, y + MENU), aff1);
	set_cursor (0, YMAX);
	termputstr ("\n", affmax);
	termputstr (tgoto (cCS, YMAX + MENU, 0), aff1);
	termputstr (cRC, aff1);
  }
}

void
set_cursor (x, y)
  register int x;
  register int y;
{
  current_cursor_y = y;
  termputstr (tgoto (cCM, x, y + MENU), aff1);
}

void
reverse_on ()
{
  termputstr (cMR, aff1);
/*
  termputstr (cSO, aff1);
*/
}

void
reverse_off ()
{
  termputstr (cME, aff1);
/*
  termputstr (cSE, aff1);
*/
}

void
altcset_on ()
{
  if (use_pc_block_graphics) {
	termputstr (cS2, aff1);
  } else {
	termputstr (cAS, aff1);
  }
}

void
altcset_off ()
{
  if (use_pc_block_graphics) {
	termputstr (cS3, aff1);
  } else {
	termputstr (cAE, aff1);
  }
}

void
disp_cursor (visible)
  FLAG visible;
{
	if (visible) {
		/* first turn it "normal" in case "very visible" does 
		   not work, then try "very visible"
		 */
		termputstr (cVE, affmax);
		termputstr (cVS, affmax);
	} else {
		termputstr (cVI, affmax);
	}
}

static
void
start_screen_mode (kb)
  int kb;
{
  if (kb) {
	/* adjust control sequences */
	if (! init_done) {
		/* if termcap/terminfo defines combined control sequences that 
		   set/reset both application cursor keys and application 
		   keypad mode, reduce them to application cursor keys only in 
		   order to maintain distinguishable control-keypad-keys
		 */
		if (! use_appl_keypad) {
			if (strncmp (cKS, "\033[?1h", 5) == 0) {
				cKS = "\033[?1h";
			}
			if (strncmp (cKE, "\033[?1l", 5) == 0) {
				cKE = "\033[?1l";
			}
		}
		if (! use_appl_cursor) {
			if (strncmp (cKS, "\033[?1h", 5) == 0) {
				cKS += 5;
			}
			if (strncmp (cKE, "\033[?1l", 5) == 0) {
				cKE += 5;
			}
		}
	}

	/* set keyboard modes */
	termputstr (cKS, affmax);

	/* set mouse modes */
	if (use_mouse) {
#ifdef debug_mouse
 		printf ("starting mouse mode\n");
#endif
		putescape (cMouseX10On);	/* activate mouse reporting */
		putescape (cMouseButtonOn);
		putescape (cMouseEventBtnOn);
		if (use_mouse_anymove_always) {
			putescape (cMouseEventAnyOn);
		}
		putescape (cMouseFocusOn);	/* activate focus reports */
		putescape (cMouseAmbigOn);	/* activate ambiguous width change reports */
		if (use_mouse_hilite_tracking) {
#ifndef dynamic_hilite_tracking
			/* activate hilite tracking */
			mouse_hilite_mode (True);
#endif
#ifdef dynamic_hilite_tracking__weird
			/* switch on and off again to enable initial hilite */
			mouse_hilite_mode (True);
			mouse_hilite_mode (False);
#endif
		}
	}
  } else {
	/* set screen modes */
	termputstr (cTI, affmax);
	termputstr (cVS, affmax);

	/* install correct scrolling region in case terminal is bigger than assumed */
	/* (this effect was observed after window size changes of Sun windows): */
	if (cCS) {
		termputstr (tgoto (cCS, YMAX + MENU, 0), aff1);
	}
  }
}

static
void
end_screen_mode ()
{
  /* reset mouse modes */
  if (use_mouse_hilite_tracking) {
	/* abort hilite tracking */
	mouse_hilite_tracking_off ();
  }

  if (use_mouse) {
# ifdef debug_hilite_tracking
	printf ("disabling hilite tracking (mode)\n");
# endif
	putescape (cMouseHighlightOff);
	is_mouse_hilite_mode_enabled = False;

	putescape (cMouseFocusOff);
	putescape (cMouseAmbigOff);
	putescape (cMouseEventBtnOff);
	putescape (cMouseButtonOff);
	putescape (cMouseX10Off);
#ifdef debug_mouse
	printf ("ended mouse mode\n");
#endif
  }
  /* if mouse was released quickly after, e.g., QUIT command, 
     swallow mouse release report already sent */
  if (char_ready_within (50, NIL_PTR)) {
	(void) _readchar_nokeymap ();
  }

  /* reset keyboard modes */
  termputstr (cKE, affmax);

  /* reset screen modes */
  termputstr (cVE, affmax);
  termputstr (cTE, affmax);

  flush ();
}


#define dont_debug_termcap

#ifdef debug_termcap
/**
   Debug termcap control strings.
 */
static
void
print_termcapstr (name, s)
  char * name;
  char * s;
{
  printf ("%s: ", name);
  if (s) {
    while (* s) {
	if ((* s & 0xE0) == 0) {
		printf ("^%c", * s + 0x40);
	} else {
		printf ("%c", * s);
	}
	s ++;
    }
  } else {
    printf ("(NULL)");
  }
  printf ("\n");
}
#endif


static
void
get_term_cap (TERMname)
  char * TERMname;
{
#ifdef TERMCAP
  char term_rawbuf [2048];
#endif

  char * check;

  if (! term_setup (TERMname)) {
	if (! streq (TERMname, "cygwin")) {
		panic ("Unknown terminal", TERMname);
	} else {
		/* fallback to support cygwin version
		   without cygwin (and esp. termcap/terminfo) installed */
		YMAX = 23;
		XMAX = 79;
		getwinsize ();
		cCL = "[H[J";
		cCE = "[K";
		cEC = "[%dX";
		cSR = "M";
		cAL = "[L";
		cDL = "[M";
		cCS = NIL_PTR;
		cSC = "7";
		cRC = "8";
		cCM = "[%i%p1%d;%p2%dH";
		cSO = "[7m";
		cSE = "[27m";
		cVS = NIL_PTR;
		cVE = NIL_PTR;
		cVI = NIL_PTR;
		cTI = "7[?47h";
		cTE = "[2J[?47l8";
		cKS = NIL_PTR;
		cKE = NIL_PTR;
		cAS = "[11m";
		cAE = "[10m";
		cEA = NIL_PTR;
		cAC = NIL_PTR;
		cS2 = "[11m";
		cS3 = "[10m";
		cME = "[0m";
		cMR = "[7m";
		cMH = NIL_PTR;
		cMD = "[1m";
		cMB = "[5m";
		cAF = NIL_PTR;
		cAB = NIL_PTR;
		cSf = NIL_PTR;
		cSb = NIL_PTR;
	}
  } else {

	/* get screen size */
	YMAX = term_getnum ("li", "lines") - 1 - MENU;	/* # of lines */
	XMAX = term_getnum ("co", "cols") - 1;	/* # of columns */
/* getenv ("LINES"), getenv ("COLUMNS") ?! */
	getwinsize ();

	/* get screen control escape sequences */
	cCL = term_getstr ("cl", "clear");	/* clear screen */
	cCE = term_getstr ("ce", "el");		/* clear to end of line */
	cEC = term_getstr ("ech", "ec");	/* erase characters */
	cSR = term_getstr ("sr", "ri");		/* scroll reverse */
	cAL = term_getstr ("al", "il1");	/* add line */
	if (!cSR) {
		cSR = cAL;
	}
	cDL = term_getstr ("dl", "dl1");	/* delete line */
	cCS = term_getstr ("cs", "csr");	/* change scrolling region */
	cSC = term_getstr ("sc", "sc");	/* save cursor    \ needed with VT100   */
	cRC = term_getstr ("rc", "rc");	/* restore cursor / for add/delete line */
	cCM = term_getstr ("cm", "cup");	/* cursor motion */
	cSO = term_getstr ("so", "smso");	/* standout mode */
	cSE = term_getstr ("se", "rmso");	/* end " */
	cVS = term_getstr ("vs", "cvvis");	/* visual cursor */
	cVE = term_getstr ("ve", "cnorm");	/* normal cursor */
	cVI = term_getstr ("vi", "civis");	/* invisible cursor */
	cTI = term_getstr ("ti", "smcup");	/* positioning mode */
	cTE = term_getstr ("te", "rmcup");	/* end " */
	cKS = term_getstr ("ks", "smkx");	/* keypad mode */
	cKE = term_getstr ("ke", "rmkx");	/* end " */
	cAS = term_getstr ("as", "smacs");	/* alternate character set */
	cAE = term_getstr ("ae", "rmacs");	/* end " */
	cEA = term_getstr ("eA", "enacs");	/* enable " */
	cAC = term_getstr ("ac", "acsc");	/* block graphics code mapping */
	cS2 = term_getstr ("S2", "smpch");	/* PC character set */
	cS3 = term_getstr ("S3", "rmpch");	/* end " */
	cME = term_getstr ("me", "sgr0");	/* end all modes */
	cMR = term_getstr ("mr", "rev");	/* reverse */
	cMH = term_getstr ("mh", "dim");	/* dim / half-bright */
	cMD = term_getstr ("md", "bold");	/* bold / extra bright */
	cMB = term_getstr ("mb", "blink");	/* blink */

	standout_glitch = term_getflag ("xs", "xhp");	/* standout glitch */

	/* check colour capability and controls */
	cAF = term_getstr ("AF", "setaf");	/* set foreground colour */
	cAB = term_getstr ("AB", "setab");	/* set background colour */
	cSf = term_getstr ("Sf", "setf");	/* set foreground colour */
	cSb = term_getstr ("Sb", "setb");	/* set background colour */
	if (term_getnum ("Co", "colors") == 0 && ! cAF && ! cSf) {
		bw_term = True;
	}

#ifdef debug_termcap_full
	printf ("%s %d %d; cCL %s, cCE %s, cEC %s, cSR %s, cAL %s,	cSR %s, cDL %s, cCS %s, cSC %s, cRC %s, cCM %s, cSO %s, cSE %s, cVS %s, cVE %s, cVI %s, cTI %s, cTE %s, cKS %s, cKE %s, cAS %s, cAE %s, cEA %s, cS2 %s, cS3 %s, cME %s, cMR %s, cMH %s, cMD %s, cMB %s, cAF %s, cAB %s, cSf %s, cSb %s\n",
		TERMname, YMAX, XMAX, 
		cCL, cCE, cEC, cSR, cAL, cSR, cDL, cCS, cSC, cRC, cCM, cSO, cSE, cVS, cVE, cVI, cTI, cTE, cKS, cKE, cAS, cAE, cEA, cS2, cS3, cME, cMR, cMH, cMD, cMB, cAF, cAB, cSf, cSb);
#endif

	/* add function key escape sequences */
	add_terminfo_entries ();
  }
#ifdef debug_termcap
  print_termcapstr ("cm", cCM);
  print_termcapstr ("AF", cAF);
  print_termcapstr ("AB", cAB);
  print_termcapstr ("Sf", cSf);
  print_termcapstr ("Sb", cSb);
  print_termcapstr ("as", cAS);
  print_termcapstr ("eA", cEA);
#endif

#ifdef TERMCAP
  if (term_capbufpoi > term_capbuf + term_capbuflen) {
	panic ("Terminal control strings don't fit", NIL_PTR);
  }
#endif

  /* derive and fix properties */

  if (cAL || (cSR && cCS)) {
	can_add_line = True;
  } else {
	can_add_line = False;
  }
  if (cSR) {
	can_scroll_reverse = True;
  } else {
	can_scroll_reverse = False;
  }
  if (cDL || cCS) {
	can_delete_line = True;
  } else {
	can_delete_line = False;
  }
  if (cCE) {
	can_clear_eol = True;
  } else {
	can_clear_eol = False;
  }
  if (cEC) {
	can_erase_chars = True;
  } else {
	can_erase_chars = False;
  }
  if (cVI) {
	can_hide_cursor = True;
  }
  if (cMH) {
	can_dim = True;
  }

#define denull(c)	if (c == NIL_PTR) c = ""

  denull (cSO);
  denull (cSE);
  denull (cTI);
  denull (cTE);
  denull (cVS);
  denull (cVE);
  denull (cVI);
  denull (cAS);
  denull (cAE);
  denull (cEA);
  denull (cAC);
  denull (cS2);
  denull (cS3);
  denull (cKS);
  denull (cKE);
  denull (cME);
  denull (cMR);
  denull (cMH);
  denull (cMD);
  denull (cMB);
  denull (cAF);
  denull (cAB);
  denull (cSf);
  denull (cSb);

  /* if the terminal has no explicit "reverse" control, use standout instead */
  if (* cMR == '\0') {
	cMR = cSO;
	cME = cSE;
  }
  if (* cMR == '\0') {
	can_reverse_mode = False;
  }

  if (!cCL || !cCM /* || !cSO || !cSE */ ) {
	panic ("Sorry, terminal features are insufficient for mined", NIL_PTR);
  }

  /* check if terminal accepts ANSI control sequence patterns */
  check = cME;
  if (* check == '\0') {
	check = cSE;
  }
  if (strcontains (check, "\033[") && strchr (check, 'm') != NIL_PTR) {
	ansi_esc = True;
  } else {
	ansi_esc = False;
  }
#ifdef debug_termcap
  print_termcapstr ("me", cME);
  print_termcapstr ("se", cSE);
  print_termcapstr ("check", check);
  printf ("ansi_esc %d\n", ansi_esc);
#endif

  /* set mouse mode controls */
  if (! ansi_esc) {
	/* disable xterm mouse escape sequences */
	cMouseX10On = "";
	cMouseX10Off = "";
	cMouseButtonOn = "";
	cMouseButtonOff = "";
	cMouseHighlightOn = "";
	cMouseHighlightOff = "";
	cMouseEventBtnOn = "";
	cMouseEventBtnOff = "";
	cMouseEventAnyOn = "";
	cMouseEventAnyOff = "";
	cMouseFocusOn = "";
	cMouseFocusOff = "";
	cMouseAmbigOn = "";
	cMouseAmbigOff = "";
  }

  if (* cAS == '\0') {
	if (use_vt100_block_graphics) {
		cAS = "";
		cAE = "";
	}
  }
  if (strcontains (TERMname, "linux") && use_vt100_block_graphics) {
	cAS = "";
	cAE = "";
  }
#ifdef terminal_already_detected
  /* which is not the case... */
  if (mintty_version >= 400) {
	cS2 = "[11m";
	cS3 = "[10m";
  }
#endif
  if (* cAS == '\0') {
	can_alt_cset = False;
  }
  if (* cEA == '\0' && * cAS != '\0'
      && (strisprefix ("xterm", TERMname)
       || strisprefix ("rxvt", TERMname)
       || strisprefix ("konsole", TERMname)
     )) {
	/* workaround for missing eA capability in /etc/termcap */
	cEA = "\033(B\033)0";
  }
  if (* cS2 != '\0' && * cS3 != '\0') {
	use_pc_block_graphics = True;
  }

  if (* cKS == '\0' && ansi_esc) {
	/* escape sequence to enable application keypad;
	   include ESC= / ESC> for terminals that don't understand 
	   ESC[?66;1h (e.g. linux console)
	 */
	cKS = "\033=\033[?66;1h";
	cKE = "\033>\033[?66;1l";
  }

  if (* cAF == '\0' && * cSf == '\0' && ansi_esc) {
	cAF = "\033[3%dm";
	cAB = "\033[4%dm";
  }

  if (* cVI == '\0' && ansi_esc) {
	cVI = "\033[?25l";
	if (* cVE == '\0') {
		cVE = "\033[?25h";
	}
  }
}

/*------------------------------------------------------------------------*/
#endif	/* ifdef unix */


#ifdef msdos

unsigned int
get_codepage ()
{
  union REGS regs;

#ifndef __TURBOC__
  __dpmi_regs mregs;
  short parblock [2];

  mregs.x.ax = 0x440C;
  mregs.x.bx = 1;	/* device handle */
  mregs.x.cx = 0x036A;	/* 3: CON, 0x6A: query selected code page */
  mregs.x.ds = __tb >> 4;
  mregs.x.dx = __tb & 0x0F;
  mregs.x.flags |= 1;	/* preset to detect unimplemented call */
  __dpmi_int (0x21, & mregs);
  if ((mregs.x.flags & 1) == 0) {
	dosmemget (__tb, 4, parblock);
	return parblock [1];
  }
#endif

  regs.x.ax = 0xAD02;
  regs.x.cflag = 1;	/* preset to detect unimplemented call */
  regs.x.bx = 0;	/* preset to detect unset result register */
  int86 (0x2F, & regs, & regs);
  if (regs.x.cflag == 0 && regs.x.bx > 1) {
	return regs.x.bx;
  }

  regs.x.ax = 0x6601;
  regs.x.cflag = 1;	/* preset to detect unimplemented call */
  regs.x.bx = 0;	/* preset to detect unset result register */
  int86 (0x21, & regs, & regs);
  if (regs.x.cflag == 0) {
	return regs.x.bx;
  }

  return 0;
}

/*
 * checkwin checks if a screen size change has occurred
	BIOS data:
	40:4A	word	video columns
	can also be determined with INT10h, function 0Fh
	40:84	byte	video lines - 1			(EGA/VGA required)
	40:85	word	character height (pixels)	(EGA/VGA required)
	can also be determined with INT10h, function 11h/30h
 */
#ifdef __TURBOC__
static
int
checkwin ()
{
  return peek (0x40, 0x4A) != XMAX + 1
/* the following line requires EGA or VGA: */
	  || peekb (0x40, 0x84) != YMAX + MENU
	;
}
#else
#include <sys/farptr.h>

static
int
checkwin ()
{
  return _farpeekw (0x40, 0x4A) != XMAX + 1
/* the following line requires EGA or VGA: */
	  || _farpeekb (0x40, 0x84) != YMAX + MENU
	;
}
#endif

#ifdef __TURBOC__
int wincheck = 1;
#else
#ifdef ANSI
int wincheck = 1;
#endif
#endif

#ifdef __TURBOC__	/* djgpp provides its own getch */

/*
 * getch () reads in a character from keyboard. We seem to need our 
 * own low-level input routine since (at least with Turbo-C) the use 
 * of getch () from conio.h makes the runtime system switch to normal 
 * text mode on startup so that extended text modes could not be used.
 * This is really a very stupid chicane of Turbo-C.
 */
int
getch ()
{
  union REGS regs;
  int result;

#ifdef getchBIOS
  /* Don't use; for some reason, this crap doesn't work. And if it's 
     tweaked to work, it doesn't provide keypad keys. And it doesn't 
     even help to avoid ^S/^Q/^C/^P handling either.
   */
  static int BIOSgetch = -1;
  if (BIOSgetch == -1) {
	regs.h.ah = 9;
	int86 (0x16, & regs, & regs);
	if (regs.h.al & 0x40) {
		BIOSgetch = 0x20;
	} else if (regs.h.al & 0x20) {
		BIOSgetch = 0x10;
	} else {
		BIOSgetch = 0x00;
	}
  }

  regs.h.ah = BIOSgetch;
  int86 (0x16, & regs, & regs);
#else
  regs.h.ah = 0x07;
  intdos (& regs, & regs);
#endif

  result = regs.h.al;

  if (wincheck && checkwin ()) {
	winchg = True;
	interrupted = True;
#ifdef debug_winchg
	printf ("winchg\n");
#endif
  /* in MSDOS, RDwin calls getch, so it cannot be called directly here */
  }

  return result;
}

#endif /* __TURBOC__ */

void
ring_bell ()
{
  union REGS regs;

  regs.h.ah = 0x0E;
  regs.h.al = 7;
  regs.h.bh = 0;
  regs.h.bl = 0;
  int86 (0x10, & regs, & regs);
}

void
set_video_lines (r)
/* 0/1/2: 200/350/400 lines */
  int r;
{
  union REGS regs;

  regs.h.ah = 0x12;
  regs.h.bl = 0x30;
  regs.h.al = r;

  int86 (0x10, & regs, & regs);
}

int font_height = 16;
void
set_font_height (r)
/* set font height in character pixels, <= 32 */
  int r;
{
#ifdef __TURBOC__
#define useintr
#endif

#ifdef useintr
  struct REGPACK regs;

  regs.r_ax = 0x1130;
  regs.r_bx = 0;
  intr (0x10, & regs);
  regs.r_ax = 0x1110;
  regs.r_bx = r << 8;
  regs.r_cx = 256;
  regs.r_dx = 0;
/*
  regs.r_bp = 0;
  regs.r_es = 0;
*/
  intr (0x10, & regs);
#else
  union REGS regs;

  regs.h.ah = 0x11;
  regs.h.al = 0x10;
  regs.h.bh = r;
  font_height = r;
  regs.h.bl = 0;
  regs.x.cx = 256;
  regs.x.dx = 0;
/*  regs.x.bp = 0;	ignored by Turbo-C's int86 function */
/*  regs.x.es = 0;	not in structure but accepted by rotten C */
  int86 (0x10, & regs, & regs);
#endif
}

void
set_grafmode_height (r, l)
/* 0/1/2: font height 8/14/16 ; 1/2/3/n: 14/25/43/n lines */
  int r;
  int l;
{
  union REGS regs;

  regs.h.ah = 0x11;
  if (r == 0) {
	regs.h.al = 0x23;
  } else if (r == 1) {
	regs.h.al = 0x22;
  } else {
	regs.h.al = 0x24;
  }
  if (l <= 0) {
	regs.h.bl = 1;
  } else if (l <= 3) {
	regs.h.bl = l;
  } else {
	regs.h.bl = 0;
	regs.h.dl = l;
  }

  int86 (0x10, & regs, & regs);
}

void
set_fontbank (f)
/* 0..7 */
  int f;
{
  union REGS regs;

  regs.h.ah = 0x11;
  regs.h.al = 0x03;
  regs.h.bl = (f & 3) * 5 + (f & 4) * 12;

  int86 (0x10, & regs, & regs);
}

#ifdef conio
#include <conio.h>

static struct text_info scrinfo;
static unsigned char norm_attr;	/* default character colours */
static unsigned char inverse_attr;

void
clear_screen ()
{
  clrscr ();
}

void
clear_eol ()
{
  clreol ();
}

void
erase_chars (n)
  register int n;
{
  while (n -- > 0) {
	putchar (' ');
  }
}

void
scroll_forward ()
{
  set_cursor (0, YMAX);
  putchar ('\n');
}

void
scroll_reverse ()
{ /* only to be called if can_add_line or cursor is at top of screen */
  insline ();
}

void
add_line (y)
  register int y;
{ /* only to be called if can_add_line == True */
  set_cursor (0, y);
  insline ();
}

void
delete_line (y)
  register int y;
{
  set_cursor (0, y);
  delline ();
}

void
set_cursor (x, y)
{
  current_cursor_y = y;
  gotoxy (x + 1, y + MENU + 1);
}

void
reverse_on ()
{
  textattr (inverse_attr);
/*highvideo ();*/
}

void
reverse_off ()
{
  textattr (norm_attr);
/*normvideo ();*/
}

void
altcset_on ()
{}

void
altcset_off ()
{}

static
void
start_screen_mode (kb)
  int kb;
{}

static
void
end_screen_mode ()
{}

void
menu_mouse_mode (menu)
  FLAG menu;
{
  in_menu_mouse_mode = menu;
}

void
get_term ()
{
  getwinsize ();

  norm_attr = scrinfo.normattr;
  inverse_attr = ((norm_attr & 0x0F) << 4) | (norm_attr >> 4);
}

void
getwinsize ()
{
/* this has to be extended to request the current screen size */
  gettextinfo (& scrinfo);
  /* This seems to be a junk procedure since no other information than
     25 * 80 comes out in 50 lines mode */
  YMAX = scrinfo.screenheight - 1 - MENU;
  XMAX = scrinfo.screenwidth - 1;
}

#endif

#endif /* ifdef msdos */


#ifdef ANSI

/* suppress some additional termcap calls */
#define termputstr(str, aff)

/* adjust the following values to the capabilities of your ANSI driver: */
static char CUP1 [] = "\033[1;1H";
static char CUD1 [] = "\033[B";
static char CUF1 [] = "\033[C";
static char DSR [] = "\033[6n";
static char ED2 [] = "\033[2J";
static char EL [] = "\033[K";
static char IL1 [] = "\033[L";
static char DL1 [] = "\033[M";
static char reverse_on_str [30] = "\033[7m";	/* inverse mode */
static char reverse_off_str [30] = "\033[27m";	/* inverse off */

void
clear_screen ()
{
  putstring (ED2);
}

void
clear_eol ()
{
  if (can_clear_eol) {
	putstring (EL);
  }
}

void
erase_chars (n)
  register int n;
{
  while (n -- > 0) {
	putchar (' ');
  }
}

void
scroll_forward ()
{
  set_cursor (0, YMAX);
  putchar ('\n');
}

void
scroll_reverse ()
{ /* only to be called if can_add_line or cursor is at top of screen */
  putstring (IL1);
}

void
add_line (y)
  register int y;
{ /* only to be called if can_add_line == True */
  set_cursor (0, y);
  putstring (IL1);
}

void
delete_line (y)
  register int y;
{
  set_cursor (0, y);
  putstring (DL1);
}

void
set_cursor (x, y)
  register int x;
  register int y;
{
  static char s [11];
  current_cursor_y = y;
  build_string (s, "\033[%d;%dH", y + MENU + 1, x + 1);
  putescape (s);
}

void
reverse_on ()
{
  putescape (reverse_on_str); /* 1m | 7m | 7m    | 7;2m */
}

void
reverse_off ()
{
  putescape (reverse_off_str); /* m  | 0m | 0m 1m | m    */
}

void
altcset_on ()
{}

void
altcset_off ()
{}

static
void
start_screen_mode (kb)
  int kb;
{}

static
void
end_screen_mode ()
{}

void
menu_mouse_mode (menu)
  FLAG menu;
{
  in_menu_mouse_mode = menu;
}

static FLAG noCPR = False;

static
int
getANSIpos ()
/* returns False if indicated position is upper left corner */
/* also leaves position in XMAX+1, YMAX+1 */
/* Checks characters input against ANSI CPR (cursor position report) 
   sequence. If it does not comply, sets noCPR flag, does not check again
   and reports as if cursor had been moved. By this trick, we implement 
   the following auxiliary behaviour: If an ANSI driver cannot deliver 
   cursor reports, mined may be stuffed the screen size as its first input, 
   at the positions of an ANSI CPR sequence but embedded in different 
   characters, e.g. XX25X80XX */
{
  int result;
  if (noCPR) {
	return 1;
  }
#ifdef msdos
  wincheck = 0;	/* prevent recursive calls of checkwin and getANSIpos */
#endif
  putstring (DSR);
  flush ();
  if (_readchar_nokeymap () != '\033') {
	noCPR = True;
  }
  if (_readchar_nokeymap () != '[') {
	noCPR = True;
  }
  if (get_digits (& YMAX) != ';') {
	noCPR = True;
  }
  if (get_digits (& XMAX) != 'R') {
	noCPR = True;
  }
  (void) _readchar_nokeymap ();	/* MSDOS ANSI drivers send a final return */
  YMAX = YMAX - 1; XMAX = XMAX - 1;
#ifdef msdos
  wincheck = 1;
#endif
  result = YMAX != 0 || XMAX != 0;
  return result;
}

static
int
failANSI (check)
/* returns False if control string does not change screen position */
  char * check;
{
  putstring (CUP1);
  putstring (check);
  return getANSIpos ();
}

void
get_term ()
{
  char * colstr = unnull (getenv ("MINEDCOL"));
  char * colrev = colstr;
  while (* colrev != '\0' && * colrev != ' ') {
	colrev ++;
  }
  if (* colrev == ' ') {
	* colrev = '\0';
	colrev ++;
  }

/* first do some harmless checks to set noCPR if simple ANSI driver */
/*
  if (failANSI (EL)) {
	can_clear_eol = False; probably every driver can do this;
  }
*/
  if (failANSI (DL1)) {
	can_delete_line = False;
  }
  if (failANSI (IL1)) {
	can_add_line = False;
	can_scroll_reverse = False;
  }

/* heuristics: if driver cannot delete line we assume if can neither set 
   extended attributes like our default inverse and inverse off,
   so change the default */
  if (can_delete_line == False) {
	build_string (reverse_off_str, "\033[32;40m");
	build_string (reverse_on_str, "\033[30;42m");
  }

/* if MINEDCOL set, use it for display attributes instead of defaults */
  if (* colstr != '\0') {
	build_string (reverse_off_str, "\033[%sm", colstr);
  }
  if (* colrev != '\0') {
	build_string (reverse_on_str, "\033[%sm", colrev);
  }

/* if cursor reports are available, check display attribute strings */
  if (noCPR == False) {
	if (failANSI (reverse_on_str)) {
		panic ("Invalid control sequence for exposed display", NIL_PTR);
	}
	if (failANSI (reverse_off_str)) {
		panic ("Invalid control sequence for normal display", NIL_PTR);
	}
  }

  getwinsize ();
}

void
getwinsize ()
{
#define stepcur 9
  int oldx = -1; int oldy = -1;
  int i;
  if (noCPR == False) {
	putstring (CUP1);
	XMAX = 0; YMAX = 0;
	do {
		for (i = 0; i < stepcur; i ++) {
			if (oldx < XMAX) {
				putstring (CUF1);
			}
			if (oldy < YMAX) {
				putstring (CUD1);
			}
		}
		oldx = XMAX + (stepcur - 1);
		oldy = YMAX + (stepcur - 1);
		(void) getANSIpos ();
	} while (oldx < XMAX || oldy < YMAX);
  }
  if (getenv ("LINES")) {
	(void) scan_int (getenv ("LINES"), & YMAX);
	YMAX --;
  }
  if (getenv ("COLUMNS")) {
	(void) scan_int (getenv ("COLUMNS"), & XMAX);
	XMAX --;
  }
  if (getenv ("NOCLEAREOL")) {
	can_clear_eol = False;	/* for debugging */
  }
  if (getenv ("NORSCROLL")) {
	can_scroll_reverse = False;	/* for debugging */
  }
/*  set_cursor (999, 999); */
/*  (void) getANSIpos (); */
  if (MENU) {
	YMAX --;
  }
}

#endif	/* ifdef ANSI */


/**************************************************************************
 * screen mode setting functions, alternatively by MSDOS BIOS calls or 
 * ANSI sequences
 */

static int textmode_height = 2;

#ifdef msdos

void
set_screen_mode (m)
  int m;
{
  union REGS regs;

  if (m >= 0) {
	regs.h.ah = 0x00;
	regs.h.al = m;
	int86 (0x10, & regs, & regs);
  }
}

void
set_textmode_height (r)
/* 0/1/2: font height 8/14/16 */
  int r;
{
  union REGS regs;

  regs.h.ah = 0x11;
  regs.h.bl = 0;
  textmode_height = r;
  if (r == 0) {
	regs.h.al = 0x12;
  } else if (r == 1) {
	regs.h.al = 0x11;
  } else {
	regs.h.al = 0x14;
  }

  int86 (0x10, & regs, & regs);
}

#else /* ifdef msdos - else use ANSI driver: */

int screen_mode = 3	/* just an assumption, cannot be determined */;

void
set_screen_mode (m)
  int m;
{
  char resize_str [8];

  if (m >= 0) {
	if (m != 50 && m != 43) {
		screen_mode = m;
	}
	build_string (resize_str, "\033[=%dh", m);
	putescape (resize_str);
  }
}

void
set_textmode_height (r)
/* 0/1/2: font height 8/14/16 */
  int r;
{
  textmode_height = r;
  if (r == 0) {
	set_screen_mode (50);
  } else if (r == 1) {
	set_screen_mode (43);
  } else {
	set_screen_mode (screen_mode);
  }
}

#endif

void
switch_textmode_height (cycle)
/* True: cycle through font heights 8/14/16 
   False: switch between font heights 8/16 */
  FLAG cycle;
{
  if (textmode_height >= 2) {
	set_textmode_height (0);
  } else if (cycle) {
	set_textmode_height (textmode_height + 1);
  } else {
	set_textmode_height (2);
  }
}


#define djconiox
#ifdef djconio

int ltab [] = {25, 28, 35, 40, 43, 50};

void
maximize_restore_screen ()
{
}

void
resize_the_screen (sb, keep_columns)
  FLAG sb;
  FLAG keep_columns;
{
/*  char resize_str [8]; */
  int lins = YMAX + 1;
  int i;

  if (sb == BIGGER) {
	i = 0;
	while (i < arrlen (ltab) && ltab [i] <= lins) {
		i ++;
	}
	if (i == arrlen (ltab)) {
		i = 0;
	}
  } else {
	i = arrlen (ltab) - 1;
	while (i >= 0 && ltab [i] >= lins) {
		i --;
	}
	if (i < 0) {
		i = arrlen (ltab) - 1;
	}
  }
  _set_screen_lines (ltab [i]);
}

#else	/* ifdef djconio */

#include "dosvideo.t"

#ifdef msdos

void
maximize_restore_screen ()
{
}

void
resize_the_screen (sb, keep_columns)
  FLAG sb;
  FLAG keep_columns;
{
/*  char resize_str [8]; */
  int totalchars = (XMAX + 1) * (YMAX + 1);
  int newtotal = 0;
  int curtotal;
  int newmode = -1;
  int i;

  if (keep_columns && ((sb == SMALLER && textmode_height > 0)
			|| (sb == BIGGER && textmode_height < 2)))
  {
	if (sb == SMALLER) {
		set_textmode_height (textmode_height - 1);
	} else {
		set_textmode_height (textmode_height + 1);
	}
  }
  else
  {
     i = 0;
     while (modetab [i].mode >= 0) {
	curtotal = modetab [i].cols * modetab [i].lins;
	if (((sb == SMALLER && curtotal < totalchars && curtotal > newtotal) ||
	     (sb == BIGGER && curtotal > totalchars && (newtotal == 0 || curtotal < newtotal)))
	    && (keep_columns == False || modetab [i].cols == XMAX + 1))
	{
		newtotal = curtotal;
		newmode = modetab [i].mode;
	}
	i ++;
     }
     if (newmode >= 0) {
	set_screen_mode (newmode);
	if (keep_columns) {
		if (sb == BIGGER) {
			set_textmode_height (0);
		} else {
			set_textmode_height (2);
		}
	}
     }
  }
}

#else

static FLAG maximised = False;

void
maximize_restore_screen ()
{
  if (maximised) {
	putescape ("\033[9;0t");
	maximised = False;
  } else {
	putescape ("\033[9;1t");
	maximised = True;
  }
}

static
void
resize_screen (l, c)
  int l;
  int c;
{
  static char s [15];
  build_string (s, "\033[8;%d;%dt", l, c);
  putescape (s);
}

void
resize_the_screen (sb, keep_columns)
  FLAG sb;
  FLAG keep_columns;
{
  int ldif = 6;
  int coldif = 13;
  if (sb == SMALLER) {
	ldif = - ldif;
	coldif = - coldif;
  }
  if (keep_columns) {
	coldif = 0;
  }

  resize_screen (YMAX + 1 + MENU + ldif, XMAX + 1 + coldif);
}

#endif

#endif


#endif	/* ifdef CURSES - else */


/*======================================================================*\
	OS input
\*======================================================================*/

/*
 * Read a character from the operating system and handle interrupts.
 * Concerning problems due to the interference of read operations and
 * incoming signals (QUIT, WINCH) see the comments at readchar ().
 */

#ifdef selectread

static
int
strange (err)
  char * err;
{
  ring_bell ();
  error2 ("Interrupted while reading from terminal: ", err);
  sleep (1);
  ring_bell ();
  return quit_char;
}

#endif


#ifndef FD_SET
#define intfds
#endif

/*
 * Is a character available within msec milliseconds from file handle?
 */
int
inputreadyafter (fid, msec)
  int fid;
  int msec;
{
#ifdef selectread

#ifdef intfds
  int readfds;	/* gives compiler warnings on System V without casting */
#else
  fd_set readfds;	/* causes mined not to work in pipe mode */
#endif

  struct timeval timeoutstru;
  register int nfds;

  timeoutstru.tv_sec = msec / 1000;
  timeoutstru.tv_usec = (msec % 1000) * 1000;

#ifdef intfds
  readfds = 1 << fid;
  nfds = select (fid + 1, & readfds, 0, 0, & timeoutstru);
#else
  FD_ZERO (& readfds);
  FD_SET (fid, & readfds);
/*nfds = select (fid + 1, (fd_set *) & readfds, 0, 0, & timeoutstru);*/
  nfds = select (fid + 1, & readfds, 0, 0, & timeoutstru);
#endif

  return nfds;

#else	/* ifdef selectread */

#ifdef CURSES
  int key;
  int timerms = 0;
  #define timestep 10

  nodelay (stdscr, TRUE);
  while (timerms < msec && (key = curs_readchar ()) == ERR) {
	napms (timestep);
	timerms += timestep;
  }
  nodelay (stdscr, FALSE);
  if (key == ERR) {
	return 0;
  } else {
	ungetch (key);
	return 1;
  }
#else
  if (msec < 500) {
	return 1;
  } else {
	return 0;
  }
#endif

#endif
}


/*
 * Read a char from operating system, handle interrupts if possible, 
 * handle window size changes if possible.
 */

#define dont_debug__readchar

#ifdef debug__readchar
#define trace__readchar(params)	printf params
#else
#define trace__readchar(params)
#endif


#ifdef selectread

static
int
__readchar_reporting_winchg (report_winchg)
  FLAG report_winchg;
{
#ifndef _getch_
  character c;
  register int n;
#endif

#ifdef intfds
  int readfds;
  int exceptfds;	/* comments see above */
#else
  fd_set readfds;
  fd_set exceptfds;
#endif

  trace__readchar (("-> __readchar\n"));
  do {
	trace__readchar (("__readchar loop\n"));
	if (winchg) {
#ifdef debug_winchg
		printf ("__readchar -> winchg -> RDwin\n");
#endif
		trace__readchar (("< RDwin\n"));
		RDwin ();
		trace__readchar (("> RDwin\n"));
	}

/* the following would be obsolete with ISIG (termios)
   which is, however, not used anymore as it also suppresses ^\ interrupt;
   on the other hand, it is obsolete with setting VINTR to NDEF as well
 */
#ifdef __CYGWIN__
#define control_C_unsure
#endif
#ifdef CURSES
#define control_C_unsure
#endif

#ifdef control_C_unsure
	if (intr_char) {
		intr_char = False;
		return '\003';
	}
#endif

#ifdef intfds
	readfds = 1 << input_fd;
	exceptfds = readfds;
	select (input_fd + 1, & readfds, 0, & exceptfds, 0);
	if (exceptfds != 0) {
#else
	FD_ZERO (& readfds);
	FD_SET (input_fd, & readfds);
	FD_ZERO (& exceptfds);
	FD_SET (input_fd, & exceptfds);
	select (input_fd + 1, & readfds, 0, & exceptfds, 0);
	if (FD_ISSET (input_fd, & exceptfds)) {
#endif

	   if (quit) {
		trace__readchar (("select -> quit\n"));
		return quit_char;

	   } else if (winchg) {
#ifdef debug_winchg
		printf ("select -> winchg\n");
#endif
		trace__readchar (("select -> winchg\n"));
		if (report_winchg) {
#ifdef debug_winchg
			printf ("-> return RDwin\n");
#endif
			/* raise WINCH exception */
			keyproc = RDwin;
			return FUNcmd;
		}

	   } else if (intr_char) {
		trace__readchar (("select -> intr_char\n"));
		intr_char = False;
		return '\003';

	   } else {
		trace__readchar (("select -> strange\n"));
		return strange ("exception");
	   }
	} else {
#ifdef _getch_
	   return getch ();
#else
	   n = read (input_fd, & c, 1);
	   if (n == 1) {
		trace__readchar (("read -> %02X\n", c));
		return c;
	   } else if ((n == 0) || (geterrno () != EINTR)) {
		trace__readchar (("read -> EINTR\n"));
		panicio ("Error during character input", serror ());
	   } else {
		trace__readchar (("read -> strange\n"));
		return strange (serror ());
	   }
#endif
	}
  } while (1);
/* NOTREACHED */
}

#else	/* ifdef selectread */

static
int
__readchar_reporting_winchg (report_winchg)
  FLAG report_winchg;
{
#ifdef _getch_

  int c;

#ifdef dosmouse
  c = mousegetch ();
#else
  c = getch ();
#endif

  if (intr_char) {
	intr_char = False;
	c = '\003';
  }

#else	/* _getch_ */

  character c;

  if (read (input_fd, & c, 1) != 1 && quit == False) {

	if (geterrno () == EINTR) {
#ifdef debug_winchg
	printf ("winchg\n");
#endif
		return __readchar ();
	} else {
		panicio ("Error during character input", serror ());
	}
  }

#endif	/* else _getch_ */

  if (quit) {
	c = quit_char;
  }

  return c;
}

#endif	/* else ifdef selectread */

int
__readchar ()
{
  return __readchar_reporting_winchg (False);
}

int
__readchar_report_winchg ()
{
  return __readchar_reporting_winchg (True);
}


/*======================================================================*\
	enquire terminal properties
\*======================================================================*/

#ifdef vms

void
get_term ()
{
  get_term_cap (NIL_PTR);
}

void
getwinsize ()
{
/* Can this be determined on VMS? Any advise by someone? */
}

#endif /* vms */

#ifdef unix

/*
   Should window size be determined with ioctl TIOCGWINSZ?
   On SunOS, the bug was seen, that after a first return value of 
   "0 0" (size not known to SunOS), further calls return junk values 
   that may crash mined.
   So further calls are prevented now if the size cannot be determined.
 */
static int get_winsz = 1;

#ifdef CURSES
# ifdef __PDCURSES__
# define has_resize_term
# endif
# ifdef NCURSES_VERSION
# define has_resize_term
# endif
#endif

/*
 * Get current window size
 */
void
getwinsize ()
{
#ifdef TIOCGWINSZ
  struct winsize winsiz;

  if (get_winsz) {
	(void) ioctl (output_fd, TIOCGWINSZ, & winsiz);
	if (winsiz.ws_row != 0) {
		YMAX = winsiz.ws_row - 1 - MENU;
	}
	if (winsiz.ws_col != 0) {
		XMAX = winsiz.ws_col - 1;
	} else {
		get_winsz = 0;
	}
  }
#else
#ifdef TIOCGSIZE
  struct ttysize ttysiz;

  (void) ioctl (output_fd, TIOCGSIZE, & ttysiz);
  if (ttysiz.ts_lines != 0) {
	YMAX = ttysiz.ts_lines - 1 - MENU;
  }
  if (ttysiz.ts_cols != 0) {
	XMAX = ttysiz.ts_cols - 1;
  }
#else
#ifdef WIOCGETD
  struct uwdata uwdat;

  (void) ioctl (output_fd, WIOCGETD, & uwdat);
  if (uwdat.uw_height > 0) {
	YMAX = uwdat.uw_height / uwdat.uw_vs - 1 - MENU;
  }
  if (uwdat.uw_width > 0) {
	XMAX = uwdat.uw_width / uwdat.uw_hs - 1;
  }
#else
/* Who can tell me how to do this on different systems? */
  error ("Cannot determine window size");
  sleep (2);
  /* leave previous size assumption */
  return;
#endif
#endif
#endif

#ifdef has_resize_term
  if (init_done) {
	resize_term (YMAX + 1 + MENU, XMAX + 1);
  }
#endif

#ifdef debug_winchg
  printf ("winsize: %d * %d\n", XMAX + 1, YMAX + 1 + MENU);
#endif
}

/*
 * Get terminal information
 */
void
get_term ()
{
  char * TERMname = getenv ("TERM");

  if (TERMname == NIL_PTR) {
#ifdef __EMX__
	TERMname = "ansi";
#else
	panic ("Terminal not specified", NIL_PTR);
#endif
  }

  get_term_cap (TERMname);
  if (strisprefix ("xterm", TERMname)) {
	window_string_code = "\033]2;%s%s\007\033]1;%s%s\007";
	colours_256 = True;
#ifdef debug_mouse
	if (use_mouse_hilite_tracking == NOT_VALID) {
		use_mouse_hilite_tracking = False;
	} else {
		use_mouse_hilite_tracking = True;
	}
#else
	use_mouse_hilite_tracking = True;
#endif
  } else if (strisprefix ("rxvt", TERMname)) {
	window_string_code = "\033]2;%s%s\007\033]1;%s%s\007";
	/* colour mode doesn't work with older buggy rxvt after configure --enable-text-blink --disable-256-color */
	colours_256 = False;
	/* recent rxvt reduced support to 88 colours */
	colours_88 = True;
  }
#ifndef CURSES
  else if (streq (TERMname, "cygwin")) {
	window_string_code = "\033]2;%s%s\007\033]1;%s%s\007";
	if (explicit_border_style) {
		use_vga_block_graphics = False;
	} else {
		use_vt100_block_graphics = False;
		use_pc_block_graphics = True;
	}
  }
#endif
  else if (strncmp (TERMname, "sun", 3) == 0 && ! streq (ttyname (output_fd), "/dev/console")) {
	window_string_code = "\033]l%s%s\033\\\033]L%s%s\033\\";
  } else if (strisprefix ("aixterm", TERMname)) {
	window_string_code = "\033]2;%s%s\007\033]1;%s%s\007";
  } else if (strisprefix ("dtterm", TERMname)) {
	window_string_code = "\033]2;%s%s\007\033]1;%s%s\007";
  } else if (strisprefix ("iris-", TERMname)) {
	window_string_code = "\033P1.y%s%s\033\\\033P3.y%s%s\033\\";
  } else if (strisprefix ("hpterm", TERMname)) {
	window_string_code = "\033&f0k%dD%s%s\033&f-1k%dD%s%s";
  } else {
	window_string_code = "";
  }

  if (no_window_title) {
	window_string_code = "";
  }

  if (! ansi_esc) {
	use_mouse_hilite_tracking = False;
	use_mouse_button_event_tracking = False;
  }

/*
  build_string (text_buffer, "Terminal is %s, %d * %d.\n", TERMname, YMAX+1, XMAX+1);
  putstring (text_buffer);
*/

#ifndef CURSES
/* enable alternate character set */
  termputstr (cEA, aff1);
#endif
}

#endif	/* ifdef unix */


#ifdef msdos	/* and not __TURBOC__ ... */
#ifdef CURSES

void
get_term ()
{
  get_term_cap ("");
}

void
getwinsize ()
{
  get_term_cap ("");
}

#endif
#endif


/*======================================================================*\
	screen attribute control
\*======================================================================*/

static
int
rgb (col)
  int col;
{
	if (col < 16) {
		if (col >= 8) {
			return rgb (col - 8);
		}
		switch (col) {
		case 0:	/* black */
			return 0x000000;
		case 1:	/* red */
			return 0xFF0000;
		case 2:	/* green */
			return 0x00FF00;
		case 3:	/* yellow */
			return 0xFFFF00;
		case 4:	/* blue */
			return 0x0000FF;
		case 5:	/* magenta */
			return 0xFF00FF;
		case 6:	/* cyan */
			return 0x00FFFF;
		case 7:	/* white */
			return 0xFFFFFF;
		default:	return 0;
		}
	} else if (col >= 232) {
		int gray = (col - 231) * 256 / 25;
		return gray << 16 | gray << 8 | gray;
	} else {
		int r, g, b;
		col -= 16;
		r = col / 36;
		g = (col % 36) / 6;
		b = col % 6;
		r *= 0x33;
		g *= 0x33;
		b *= 0x33;
		return r << 16 | g << 8 | b;
	}
}

static
int
R (rgb0)
  int rgb0;
{
	return rgb0 / 36;
}

static
int
G (rgb0)
  int rgb0;
{
	return (rgb0 % 36) / 6;
}

static
int
B (rgb0)
  int rgb0;
{
	return rgb0 % 6;
}

static
unsigned int
dist (rgb1, rgb2)
  int rgb1, rgb2;
{
	int dr = R (rgb1) - R (rgb2);
	int dg = G (rgb1) - G (rgb2);
	int db = B (rgb1) - B (rgb2);
	return dr * dr + dg * dg + db * db;
}

static
int
map8 (col)
  int col;
{
	unsigned int d = (unsigned int) -1;	/* max unsigned int */
	int i;
	int rgb_col = rgb (col);
	int repl_col = -1;

	if (col >= 244) {
		return 7;
	} else if (col >= 232) {
		return 0;
	}
	for (i = 0; i < 8; i ++) {
		unsigned int dist_col = dist (rgb (i), rgb_col);
		if (dist_col < d) {
			d = dist_col;
			repl_col = i;
		}
	}
	return repl_col;
}


#ifdef CURSES

/* colour definitions from curses.h
// #define COLOR_BLACK     0
// #define COLOR_RED       1
// #define COLOR_GREEN     2
// #define COLOR_YELLOW    3
// #define COLOR_BLUE      4
// #define COLOR_MAGENTA   5
// #define COLOR_CYAN      6
// #define COLOR_WHITE     7
*/
/* colour pair index definitions */
#define ctrlcolor (short) 1
#define markcolor (short) 4
#define emphcolor (short) 9
#define combiningcolor (short) 13
#define menucolor (short) 2
#define menuborder (short) 10
#define menuheader (short) 11
#define menuitem (short) 12
#define selcolor (short) 17
#define selfgcolor (short) 18
#define diagcolor (short) 3
#define unicolor (short) 7
#define unimarkcolor (short) 8
#define scrollfgcolor (short) 5
#define scrollbgcolor (short) 6
#define HTMLcolor (short) 14
#define HTMLcomment (short) 15
#define HTMLjsp (short) 16
#define colour8_base 18

#if NCURSES_VERSION_MAJOR >= 5
#define use_default_colour
#endif
#if NCURSES_VERSION_MAJOR == 4
# if NCURSES_VERSION_MINOR >= 2
#define use_default_colour
# endif
#endif

#ifdef use_default_colour
#define COLOR_fg (short) -1
#define COLOR_bg (short) -1
#else
#define COLOR_fg (short) COLOR_WHITE /* should be "none" (default foreground) */
#define COLOR_bg (short) COLOR_BLACK /* should be "none" (default background) */
#endif

static
void
init_colours ()
{
  start_color ();
#ifdef use_default_colour
  use_default_colors ();
#endif
  if (! has_colors ()) {
	bw_term = True;
  }

/* This produces silly warnings if compiled with gcc option -Wconversion
   ("passing arg ... with different width due to prototype")
   although all parameters are short.
*/
  init_pair (unicolor, COLOR_fg, COLOR_CYAN);	/* analyse uniansi */
  init_pair (combiningcolor, COLOR_BLACK, COLOR_CYAN);	/* analyse combiningansi */
  init_pair (ctrlcolor, COLOR_fg, COLOR_bg);	/* analyse ctrlansi */
  init_pair (menucolor, COLOR_fg, COLOR_bg);	/* analyse menuansi */
  init_pair (diagcolor, COLOR_fg, COLOR_bg);	/* analyse diagansi */
  init_pair (markcolor, COLOR_RED, COLOR_bg);	/* analyse markansi */
  init_pair (emphcolor, COLOR_RED, COLOR_bg);	/* analyse emphansi */
  init_pair (unimarkcolor, COLOR_CYAN, COLOR_bg);	/* analyse unimarkansi */
  init_pair (scrollfgcolor, COLOR_CYAN, COLOR_BLUE);	/* analyse scrollfgansi */
  init_pair (scrollbgcolor, COLOR_BLUE, COLOR_CYAN);	/* analyse scrollbgansi */
  init_pair (menuborder, COLOR_RED, COLOR_bg);
  init_pair (menuitem, COLOR_BLACK, COLOR_YELLOW);
  init_pair (HTMLcolor, COLOR_BLUE, COLOR_bg);	/* analyse HTMLansi */
  init_pair (HTMLcomment, COLOR_BLUE, COLOR_YELLOW);	/* analyse HTMLansi */
  init_pair (HTMLjsp, COLOR_CYAN, COLOR_bg);	/* analyse HTMLansi */

  if (avoid_reverse_colour) {
	init_pair (selfgcolor, COLOR_YELLOW, COLOR_BLUE);	/* analyse selfgansi, selansi */
	init_pair (selcolor, COLOR_bg, COLOR_BLUE);	/* analyse selansi */
	init_pair (menuheader, COLOR_WHITE, COLOR_RED);
  } else {
	init_pair (selfgcolor, COLOR_BLUE, COLOR_YELLOW);	/* analyse selfgansi, selansi */
	init_pair (selcolor, COLOR_BLUE, COLOR_bg);	/* analyse selansi */
	init_pair (menuheader, COLOR_RED, COLOR_bg);
  }

  init_pair (colour8_base + 0, COLOR_BLACK, COLOR_bg);
  init_pair (colour8_base + 1, COLOR_RED, COLOR_bg);
  init_pair (colour8_base + 2, COLOR_GREEN, COLOR_bg);
  init_pair (colour8_base + 3, COLOR_YELLOW, COLOR_bg);
  init_pair (colour8_base + 4, COLOR_BLUE, COLOR_bg);
  init_pair (colour8_base + 5, COLOR_MAGENTA, COLOR_bg);
  init_pair (colour8_base + 6, COLOR_CYAN, COLOR_bg);
  init_pair (colour8_base + 7, COLOR_WHITE, COLOR_bg);
}

void
disp_colour (c)
  int c;
{
	attrset (COLOR_PAIR (colour8_base + map8 (c)));
	if (dark_term) {
		attron (A_BOLD);
	}
}

void
emph_on ()
{
	attrset (COLOR_PAIR (emphcolor));
	if (dark_term) {
		attron (A_BOLD);
	}
}

void
mark_on ()
{
	if (colour_token >= 0) {
		disp_colour (colour_token);
		colour_token = -1;
	} else if (* markansi != '\0') {
		attrset (COLOR_PAIR (markcolor));
	} else if (! dark_term) {
		attrset (A_DIM);
	}
	if (dark_term) {
		attron (A_BOLD);
	}
}

void
mark_off ()
{
	standend ();
}


void
bold_on ()
{
	attrset (A_BOLD);
}

void
bold_off ()
{
	standend ();
}

void
disp_normal ()
{
	standend ();
}

void
disp_selected (bg, border)
  FLAG bg;
  FLAG border;
/* for selected menu item */
{
/*	| selected item |
	left border: bg && border (if graphic)
	  selected item: bg && ! border
	                right border: ! bg && border (if graphic)
*/
	if (avoid_reverse_colour) {
		/* workaround for buggy cygwin reverse bold colour handling */
		if (bg) {
			if (border) {
				attrset (COLOR_PAIR (selcolor));
			} else {
				reverse_off ();
				attrset (COLOR_PAIR (selfgcolor) | A_BOLD);
			}
		} else {
			attrset ((border ? COLOR_PAIR (selcolor) : COLOR_PAIR (selfgcolor)));
		}
	} else {
		if (* selansi != '\0') {
			attrset ((border ? COLOR_PAIR (selcolor) : COLOR_PAIR (selfgcolor))
				 | (bg ? A_REVERSE : 0)
				 | (dark_term ? A_BOLD : 0)
				 );
		} else {
			standout ();
		}
	}
}


void
unidisp_on ()
/* for non-displayable or illegal Unicode characters */
{
	if (* uniansi != '\0') {
		attrset (COLOR_PAIR (unicolor));
	} else {
		standout ();
	}
}

void
unidisp_off ()
{
	standend ();
}


void
unimarkdisp_on ()
/* for Unicode line end indications */
{
	if (* unimarkansi != '\0') {
		attrset (COLOR_PAIR (unimarkcolor));
	} else {
		standout ();
	}
}

void
unimarkdisp_off ()
{
	standend ();
}


void
combiningdisp_on ()
/* for Unicode combining character indication in separated display mode */
{
	if (* combiningansi != '\0') {
		attrset (COLOR_PAIR (combiningcolor));
	} else {
		standout ();
	}
}

void
combiningdisp_off ()
{
	standend ();
}


void
ctrldisp_on ()
{
	if (* ctrlansi != '\0') {
		attrset (COLOR_PAIR (ctrlcolor));
	} else {
		standout ();
	}
}

void
ctrldisp_off ()
{
	standend ();
}


void
dispHTML_code ()
{
	if (* HTMLansi != '\0') {
		attrset (COLOR_PAIR (HTMLcolor));
	} else {
		standout ();
	}
}

void
dispHTML_comment ()
{
	if (* HTMLansi != '\0') {
		attrset (COLOR_PAIR (HTMLcomment));
	} else {
		standout ();
	}
}

void
dispHTML_jsp ()
{
	if (* HTMLansi != '\0') {
		attrset (COLOR_PAIR (HTMLjsp));
	} else {
		standout ();
	}
}

void
dispHTML_off ()
{
	standend ();
}


void
menudisp_on ()
{
	if (* menuansi != '\0') {
		attrset (COLOR_PAIR (menucolor));
	} else {
		standout ();
	}
}

void
menudisp_off ()
{
	standend ();
}

void
diagdisp_on ()
{
	if (* diagansi != '\0') {
		attrset (COLOR_PAIR (diagcolor));
	} else {
		standout ();
	}
}

void
diagdisp_off ()
{
	standend ();
}


void
disp_scrollbar_foreground ()
{
	if (* scrollbgansi != '\0') {
		attrset (COLOR_PAIR (scrollfgcolor));
	} else {
		standout ();
	}
}

void
disp_scrollbar_background ()
{
	if (* scrollbgansi != '\0') {
		attrset (COLOR_PAIR (scrollbgcolor));
	}
}

void
disp_scrollbar_off ()
{
	standend ();
}


void
menuborder_on ()
{
	if (! use_normalchars_boxdrawing) {
		altcset_on ();
	}
#ifdef use_default_colour
	attrset (COLOR_PAIR (menuborder) | A_BOLD);
#endif
	in_menu_border = True;
}

void
menuborder_off ()
{
	standend ();
	if (! use_normalchars_boxdrawing) {
		altcset_off ();
	}
	in_menu_border = False;
}

void
menuitem_on ()
{
#ifdef use_default_colour
	attrset (COLOR_PAIR (menuitem) /* | A_BOLD */);
#endif
}

void
menuitem_off ()
{
	standend ();
}

void
menuheader_on ()
{
	if (! use_normalchars_boxdrawing) {
		altcset_off ();
	}
	if (avoid_reverse_colour) {
		/* workaround for buggy cygwin reverse bold colour handling */
		disp_normal ();
		attrset (COLOR_PAIR (menuheader));
	} else {
		attrset (COLOR_PAIR (menuheader) | A_BOLD | A_REVERSE);
	}
	in_menu_border = False;
}

void
menuheader_off ()
{
	standend ();
	in_menu_border = False;
}


#else	/* ifdef CURSES */


#ifdef conio

void
disp_colour (c)
  int c;
{
	switch (map8 (c)) {
		case 0: textcolor (BLACK); break;
		case 1: textcolor (RED); break;
		case 2: textcolor (GREEN); break;
		case 3: textcolor (YELLOW); break;
		case 4: textcolor (BLUE); break;
		case 5: textcolor (MAGENTA); break;
		case 6: textcolor (CYAN); break;
		case 7: textcolor (WHITE); break;
	}
	if (dark_term) {
		highvideo ();
	}
}

void
emph_on ()
{
	/* check emphansi ? */
	textcolor (RED);
	if (dark_term) {
		highvideo ();
	}
}

void
mark_on ()
{
	/* check markansi ? */
	if (colour_token >= 0) {
		disp_colour (colour_token);
		colour_token = -1;
	} else {
		textcolor (RED);
	}
	if (dark_term) {
		highvideo ();
	}
}

void
mark_off ()
{
	normvideo ();
}


void
bold_on ()
{
	highvideo ();
}

void
bold_off ()
{
	normvideo ();
}

void
disp_normal ()
{
	normvideo ();
}

void
disp_selected (bg, border)
  FLAG bg;
  FLAG border;
{
	/* check selansi ? */
	if (bg) {
		if (dark_term) {
			highvideo ();
		} else {
			normvideo ();
		}
		textbackground (BLUE);
		if (! border) {
			textcolor (YELLOW);
		}
	} else {
		textcolor (BLUE);
	}
}


void
unidisp_on ()
/* for non-displayable or illegal Unicode characters */
{
	/* check uniansi ? */
	textbackground (CYAN);
}

void
unidisp_off ()
{
	normvideo ();
}


void
unimarkdisp_on ()
/* for Unicode line end indications */
{
	textcolor (CYAN);
}

void
unimarkdisp_off ()
{
	normvideo ();
}


void
combiningdisp_on ()
/* for Unicode combining character indication in separated display mode */
{
	textbackground (CYAN);
	textcolor (BLACK);
}

void
combiningdisp_off ()
{
	normvideo ();
}


void
ctrldisp_on ()
{
	reverse_on ();
}

void
ctrldisp_off ()
{
	reverse_off ();
}


void
dispHTML_code ()
{
	textcolor (LIGHTBLUE);
}

void
dispHTML_comment ()
{
	textcolor (LIGHTBLUE);
	textbackground (YELLOW);
}

void
dispHTML_jsp ()
{
	textcolor (CYAN);
	textbackground (BLACK);
}

void
dispHTML_off ()
{
	normvideo ();
}


void
menudisp_on ()
{
	reverse_on ();
}

void
menudisp_off ()
{
	reverse_off ();
}

void
diagdisp_on ()
{
	reverse_on ();
}

void
diagdisp_off ()
{
	reverse_off ();
}


void
disp_scrollbar_foreground ()
{
/*	textattr (CYAN);	*/
	textbackground (BLUE);
}

void
disp_scrollbar_background ()
{
/*	textattr (BLUE);	*/
	textbackground (CYAN);
}

void
disp_scrollbar_off ()
{
	normvideo ();
}


void
menuborder_on ()
{
	if (! use_normalchars_boxdrawing) {
		altcset_on ();
	}
	textattr (RED);
	highvideo ();
	in_menu_border = True;
}

void
menuborder_off ()
{
	normvideo ();
	textattr (norm_attr);
	if (! use_normalchars_boxdrawing) {
		altcset_off ();
	}
	in_menu_border = False;
}

void
menuitem_on ()
{
	textbackground (YELLOW);
	/* highvideo (); */
}

void
menuitem_off ()
{
	textattr (norm_attr);
}

void
menuheader_on ()
{
	if (! use_normalchars_boxdrawing) {
		altcset_off ();
	}
	/*reverse_on ();*/
	textbackground (RED);
	textcolor (LIGHTGRAY);
	in_menu_border = False;
}

void
menuheader_off ()
{
	textattr (norm_attr);
	in_menu_border = False;
}

#else	/* ifdef conio */

static
FLAG
putansistring (s)
  char * s;
{
	if (ansi_esc && * s != '\0') {
		putescape ("\033[");
		putescape (s);
		putescape ("m");
		return True;
	} else {
		return False;
	}
}

void
disp_colour (c)
  int c;
{
	char ctrl [19];

	if (c < 8) {
		build_string (ctrl, "3%d", c);
	} else if (c < 16) {
		build_string (ctrl, "9%d", c - 8);
	} else {
		if (colours_256 || colours_88) {
			build_string (ctrl, "38;5;%d", c);
		} else {
			build_string (ctrl, "3%d", map8 (c));
		}
	}
	(void) putansistring (ctrl);
	if (dark_term) {
		bold_on ();
	}
}

void
emph_on ()
{
	if (dark_term) {
		bold_on ();
	}
	(void) putansistring (emphansi);
}

void
mark_on ()
{
	if (dark_term) {
		bold_on ();
	} else {
		termputstr (cMH, aff1);
	}
	if (colour_token >= 0) {
		disp_colour (colour_token);
		colour_token = -1;
	} else {
		(void) putansistring (markansi);
	}
}

void
mark_off ()
{
	if (! putansistring ("0")) {
		termputstr (cME, aff1);
	}
}


void
bold_on ()
{
	if (use_bold) {
		if (! putansistring ("1")) {
			termputstr (cMD, aff1);
		}
	}
}

void
bold_off ()
{
	if (use_bold) {
		if (! putansistring ("0")) {
			termputstr (cME, aff1);
		}
	}
}

void
disp_normal ()
{
	if (! putansistring ("0")) {
		reverse_off ();
	}
}

static
char *
reverse_colour (ansi)
  char * ansi;
{
	static char revansi [3];
	if (ansi [0] == '3') {
		revansi [0] = '4';
	} else {
		revansi [0] = '3';
	}
	revansi [1] = ansi [1];
	revansi [2] = 0;
	return revansi;
}

void
disp_selected (bg, border)
  FLAG bg;
  FLAG border;
{
/*	| selected item |
	left border: bg && border (if graphic)
	  selected item: bg && ! border
	                right border: ! bg && border (if graphic)
*/
	if (avoid_reverse_colour) {
		/* workaround for buggy cygwin reverse bold colour handling */
		if (bg) {
			if (border) {
				(void) putansistring (selansi);
				reverse_on ();
			} else {
				reverse_off ();
				(void) putansistring (reverse_colour (selansi));
				(void) putansistring (reverse_colour (selfgansi));
				bold_on ();
			}
		} else {
			(void) putansistring (selansi);
			if (! border) {
				(void) putansistring (selfgansi);
			}
		}
	} else {
		(void) putansistring (selansi);
		if (! border) {
			(void) putansistring (selfgansi);
		}
		if (bg) {
			reverse_on ();
		}
	}
}


void
unidisp_on ()
/* for non-displayable or illegal Unicode characters */
{
	if (! putansistring (uniansi)) {
		reverse_on ();
	}
}

void
unidisp_off ()
{
	if (* uniansi != '\0') {
		if (! putansistring ("0")) {
			reverse_off ();
		}
	} else {
		reverse_off ();
	}
}


void
unimarkdisp_on ()
/* for Unicode line end indications */
{
	if (! putansistring (unimarkansi)) {
		reverse_on ();
	}
}

void
unimarkdisp_off ()
{
	if (* unimarkansi != '\0') {
		if (! putansistring ("0")) {
			reverse_off ();
		}
	} else {
		reverse_off ();
	}
}


void
combiningdisp_on ()
/* for Unicode combining character indication in separated display mode */
{
	if (! putansistring (combiningansi)) {
		reverse_on ();
	}
}

void
combiningdisp_off ()
{
	if (* combiningansi != '\0') {
		if (! putansistring ("0")) {
			reverse_off ();
		}
	} else {
		reverse_off ();
	}
}


void
ctrldisp_on ()
{
	if (! putansistring (ctrlansi)) {
		reverse_on ();
	}
}

void
ctrldisp_off ()
{
	if (* ctrlansi != '\0') {
		if (! putansistring ("0")) {
			reverse_off ();
		}
	} else {
		reverse_off ();
	}
}


void
dispHTML_code ()
{
	if (! putansistring (HTMLansi)) {
		mark_on ();
	}
}

void
dispHTML_comment ()
{
	char ctrl [19];

	if (* HTMLansi != '\0') {
		build_string (ctrl, "%s;43", HTMLansi);
		if (! putansistring (ctrl)) {
			mark_on ();
		}
	} else {
		mark_on ();
	}
}

void
dispHTML_jsp ()
{
	if (* HTMLansi != '\0') {
		/*(void) putansistring ("36");*/
		if (! putansistring ("36;40")) {
			mark_on ();
		}
	} else {
		mark_on ();
	}
}

void
dispHTML_off ()
{
	if (* HTMLansi != '\0') {
		if (! putansistring ("0")) {
			mark_off ();
		}
	} else {
		mark_off ();
	}
}


void
menudisp_on ()
{
	if (! putansistring (menuansi)) {
		reverse_on ();
	}
}

void
menudisp_off ()
{
	if (* menuansi != '\0') {
		if (! putansistring ("0")) {
			reverse_off ();
		}
	} else {
		reverse_off ();
	}
}

void
diagdisp_on ()
{
	if (! putansistring (diagansi)) {
		reverse_on ();
	}
}

void
diagdisp_off ()
{
	if (* diagansi != '\0') {
		if (! putansistring ("0")) {
			reverse_off ();
		}
	} else {
		reverse_off ();
	}
}


void
disp_scrollbar_foreground ()
{
	if (* scrollfgansi != '\0') {
		if (! putansistring (scrollfgansi)) {
			reverse_on ();
		}
	} else {
		(void) putansistring (scrollbgansi);
		reverse_on ();
	}
}

void
disp_scrollbar_background ()
{
	reverse_off ();
	if (! putansistring (scrollbgansi)) {
		termputstr (cSO, aff1);
	}
}

void
disp_scrollbar_off ()
{
	if (* scrollbgansi != '\0') {
		if (! putansistring ("0")) {
			reverse_off ();
		}
	} else {
		reverse_off ();
	}
}


void
menuborder_on ()
{
  FLAG bold_border = use_bold;

	if (! use_normalchars_boxdrawing) {
		altcset_on ();
	} else if (menu_border_style == 'f' || menu_border_style == 'd') {
		bold_border = False;
	}
	if (bold_border) {
		bold_on ();
	}
	(void) putansistring (borderansi);
	in_menu_border = True;
}

void
menuborder_off ()
{
	(void) putansistring ("0");
	if (! use_normalchars_boxdrawing) {
		altcset_off ();
	}
	in_menu_border = False;
}

void
menuitem_on ()
{
	if (use_bgcolor) {
		/* try to keep it visible on old buggy hanterm: */
		/* - hopefully not needed anymore; */
		/* - interferes unpleasantly with buggy 
		     bold/colour combination on gnome-terminal/konsole */
		/* bold_on (); */

		if (! putansistring ("43;30")) {
			reverse_on ();
		}
	} else {
		if (! putansistring ("0;1")) {
			reverse_on ();
		}
	}
}

void
menuitem_off ()
{
	if (! putansistring ("0")) {
		reverse_off ();
	}
}

void
menuheader_on ()
{
	if (! use_normalchars_boxdrawing) {
		altcset_off ();
	}
	if (avoid_reverse_colour) {
		/* workaround for buggy cygwin reverse bold colour handling */
		disp_normal ();
		if (dark_term) {
			(void) putansistring ("37");
		}
		(void) putansistring (reverse_colour (borderansi));
	} else {
		if (dark_term) {
			bold_on ();
		}
		/* Note: menu border colour is already switched on */
		if (! putansistring ("7")) {
			reverse_on ();
		}
	}
	in_menu_border = False;
}

void
menuheader_off ()
{
	if (! putansistring ("0")) {
		reverse_off ();
	}
	in_menu_border = False;
}

#endif	/* else ifdef conio */

#endif	/* else ifdef CURSES */


/*======================================================================*\
|*			include optional mouse API			*|
\*======================================================================*/

#ifdef dosmouse
#include "dosmouse.c"
#endif


/*======================================================================*\
|*				End					*|
\*======================================================================*/
