/*+++*
 *  title:	tmsgcap.c
 *  abstract:	(VMS) add SMG termtable lookup to standard termcap
 *  author:	T.R.Hageman, Groningen, The Netherlands.
 *  created:	July 1991
 *  modified:	08-Aug-91, make standard termcap support optional
 *			according to compilation option VMS_TERMCAP.
 *		24-Oct-91, determine order of termcap/smgcap at compile time
 *			according to the value of VMS_TERMCAP.
 *		 2-Jul-93, add PADM(ulti-line) and KEY flags.
 *		(see also RCS Log at end of header)
 *  description:
 *	This emulates the UNIX termcap routines on VMS using the SMG
 *	TERMTABLE access routines.
 *
 *	If the compile-time option VMS_TERMCAP is #defined, the names of
 *	the termcap routines in this file are prepended with "vms_", and the
 *	standard termcap is also accessed.  The value of VMS_TERMCAP determines
 *	whether termcap or SMG termcable is accessed first:
 *	  VMS_TERMCAP >= 0	first TERMCAP, then SMG
 *	  VMS_TERMCAP <  0	first SMG, then TERMCAP
 *	I found the first option the more satisfying, since it gives you
 *	easier control for fine-tuning standard DEC terminal capabilities.
 *	(by overriding it from a private termcap file.)
 *
 *	The vt100 keypad keys are hardwired to "standard" termcap keys
 *	according to the following convention:
 *		._________._________._________._________.
 *		|PF1  [k1]|PF2  [k2]|PF3  [k3]|PF4  [k4]|
 *		|_________|_________|_________|_________|
 *		| 7   [K1]| 8   [kP]| 9   [K3]| -   [kF]|
 *		|_________|_________|_________|_________|
 *		| 4   [kt]| 5   [K2]| 6   [kT]| ,   [kR]|
 *		|_________|_________|_________|_________|
 *		| 1   [K4]| 2   [kN]| 3   [K5]|Enter[kA]|
 *		|_________|_________|_________|         |
 *		| 0             [k0]| .   [ka]|         |
 *		|___________________|_________|_________|
 *
 *	The vt200 function keys are mapped as follows:
 *		f1 - f4:	[FA] - [FD]
 *		f5 - f9:	[k5] - [k9]
 *		f10:		[k;]
 *		f11 - f19:	[F1] - [F9]
 *		f20:		[F0]
 *	The vt200(?) editing keys are (rather arbitrarily?) mapped as follows:
 *		e1:		 --		(none)
 *		e2:		[kI]		(insert character)
 *		e3:		[kD]		(delete character)
 *		e4:		[kU]		(select)
 *		e5:		[kE]		(delete line)
 *		e6:		[kS]		(clear screen)
 *
 *  NOTE:
 *	This file can be compiled as a whole, but it can also be split
 *	using my srcsplit(1) program.
 *
 *  $Log: tsmgcap.c,v $
 * Revision 1.3  1993/07/03  00:52:43  tom
 * add PADM and KEY support, to keep in sync with "tinfocap.[ch]"; doc fix;
 * add RCS trivia; (_smg_tgetstr): allow NULL `pp' arg.
 *
 *---*/

/*======================================================================*/
/* #common_header							*/
/*======================================================================*/
#if vms

#include <descrip.h>
#include <iodef.h>
#include <smgtrmptr.h>
#include <stsdef.h>
#include <ttdef.h>

#ifdef DEBUG
#   include <stdio.h>
#   define DPRINTF(x)	printf x
#else
#   define DPRINTF(x)
#endif
#ifndef NULL
#   define NULL	0
#endif

/* #insert "vms-tcap.h" */

typedef struct {
	short	tcp_id;
	short	smg_id;
} Where;

#define Const const

#define SMG_SHIFT	10  /* (1<<SMG_MASK) MUST be > all SMG$K_ codes! */
#define SMG_MASK	((1<<SMG_SHIFT)-1)

#define SMG_MAX		(SMG_MASK<<2)	/* allow parameters 0 -- 3 */


/* extra options are ORed in to actual SMG$ id. */

#define PAD	0			/* dummy flags for string cap. */
#define PADM	0
#define KEY	0
#define NOT	((short)0x8000>>SMG_SHIFT)	/* negation for boolean cap. */


/* build termcap id. */
#define ident(a,b)	((a)<<8|(b))


/* ENTRY(a,b, smg_name, param, smg_id)

   Enter a capability in the table.

   "Standard" termcap entries are defined using ENTRY.
   "Extended" entries are defined using EXTRY for easy recognition,
   these define SMG capabilities for which there is no standard termcap
   equivalent.

   The tables should be lexically ordered on termcap id. (a,b)

   (some parameters are unused here, but -by means of a redefinition of
    the ENTRY macro and the Where struct- useful in other contexts; thus we
    keep all information about capabilities in a single place) */

#define ENTRY(a,b,i,p,f)	{ident(a,b), (p)<<SMG_SHIFT|f},
#define EXTRY	ENTRY

#define TABLESIZE(tab)		(sizeof(tab) / sizeof(tab[0]) -1)

#ifndef Extern
#   define Extern	extern
#endif

extern int	_termtable;
#ifdef VMS_TERMCAP
extern int	_termcap;
#   define	TERMCAP_FIRST	(VMS_TERMCAP - 0 >= 0)
#endif
extern struct termchar {		/* Terminal characteristics	*/
	char		t_class,
			t_type;
	unsigned short	t_width;		/* # of columns		*/
	unsigned	t_mode : 24;		/* flags		*/
	unsigned	t_page : 8;		/* # of lines		*/
	unsigned long	t_xmode;		/* more flags		*/
} _termchar;

#endif
/*======================================================================*/
/* #header "vms-termcap.h"						*/
/*======================================================================*/
#if vms
#define TBUFSIZE	2048	/* Assumed size of tgetent result buffer. */

#ifdef VMS_TERMCAP
#define tgetent		vms_tgetent
#define tgetflag	vms_tgetflag
#define tgetstr		vms_tgetstr
#define tgetnum		vms_tgetnum
#define tgoto		vms_tgoto
#endif
#endif
/*======================================================================*/
/* #header "vms-tflagtab.h"						*/
/*======================================================================*/
#if vms
static Const Where FlagTab[] = {
ENTRY('a','m', "auto_margin",		0,	SMG$K_AUTO_MARGIN )		/* Terminal has automatic margins */
/* ENTRY('b','w', "bw",			0,	auto_left_margin )		/* cub1 wraps from column 0 to last column */
/* ENTRY('d','a', "da",			0,	memory_above )			/* Display may be retained above the screen */
/* ENTRY('d','b', "db",			0,	memory_below )			/* Display may be retained below the screen */
/* ENTRY('e','o', "eo",			0,	erase_overstrike )		/* Can erase overstrikes with a blank */
/* ENTRY('e','s', "eslok",		0,	status_line_esc_ok )		/* Escape can be used on the status line */
/* ENTRY('g','n', "gn",			0,	generic_type )			/* Generic line type (e.g.,, dialup, switch). */
ENTRY('h','c', "scope",			NOT,	SMG$K_SCOPE )			/* Hardcopy terminal */
/* ENTRY('h','s', "hs",			0,	has_status_line )		/* Has extra "status line" */
/* ENTRY('h','z', "hz",			0,	tilde_glitch )			/* Hazeltine; can not print ~'s */
ENTRY('i','n', "insert_mode_nulls",	0,	SMG$K_INSERT_MODE_NULLS )	/* Insert mode distinguishes nulls */
/* ENTRY('k','m', "km",			0,	has_meta_key )			/* Has a meta key (shift, sets parity bit) */
/* ENTRY('m','i', "mir",		0,	move_insert_mode )		/* Safe to move while in insert mode */
/* ENTRY('m','s', "msgr",		0,	move_standout_mode )		/* Safe to move in standout modes */
ENTRY('o','s', "overstrike",		0,	SMG$K_OVERSTRIKE )		/* Terminal overstrikes */
ENTRY('u','l', "underline",		0,	SMG$K_UNDERLINE )		/* underline character overstrikes */
/* ENTRY('x','b', "xsb",		0,	beehive_glitch )		/* Beehive (f1=escape, f2=ctrl C) */
ENTRY('x','n', "ignore_newline",	0,	SMG$K_IGNORE_NEWLINE )		/* newline ignored after 80 cols (Concept) */
/* ENTRY('x','o', "xon",		0,	xon_xoff )			/* Terminal uses xon/xoff handshaking */
ENTRY('x','s', "no_erase",		0,	SMG$K_NO_ERASE )		/* Standout not erased by overwriting (hp) */
/* ENTRY('x','t', "xt",			0,	teleray_glitch )		/* Tabs ruin, magic so char (Teleray 1061) */
  {0}	/* Zero-terminate (since not all compilers can handle trailing `,') */
};
#endif
/*======================================================================*/
/* #header "vms-tnumtab.h"						*/
/*======================================================================*/
#if vms
static Const Where NumTab[] = {
EXTRY('C','O', "wide_screen_columns",	0,	SMG$K_WIDE_SCREEN_COLUMNS )	/* Number of columns wide-screen mode. */
ENTRY('c','o', "columns",		0,	SMG$K_COLUMNS )			/* Number of columns in a line */
/* ENTRY('i','t', "it",			0,	init_tabs )			/* Tabs initially every # spaces */
ENTRY('l','i', "rows",			0,	SMG$K_ROWS )			/* Number of lines on screen or page */
/* ENTRY('l','m', "lm",			0,	lines_of_memory )		/* Lines of memory if > lines.  0 means varies */
/* ENTRY('p','b', "pb",			0,	padding_baud_rate )		/* Lowest baud where cr/nl padding is needed */
/* ENTRY('s','g', "xmc",		0,	magic_cookie_glitch )		/* Number of blank chars left by smso or rmso */
/* ENTRY('v','t', "vt",			0,	virtual_terminal )		/* Virtual terminal number (HP-UX system) */
/* ENTRY('w','s', "wsl",		0,	width_status_line )		/* No. columns in status line */
  {0}	/* Zero-terminate (since not all compilers can handle trailing `,') */
};
#endif
/*======================================================================*/
/* #header "vms-tstrtab.h"						*/
/*======================================================================*/
#if vms
static Const Where StrTab[] = {
ENTRY('A','L', "insert_line",		PADM|1,	SMG$K_INSERT_LINE )		/* Add #1 new blank lines (PG*) */
/* ENTRY('C','C', "cmdch",		0,	command_character )		/* Term. settable cmd char in prototype */
/* ENTRY('C','M', "mrcup",		PADM|2,	cursor_mem_address )		/* Memory relative cursor addressing */
ENTRY('D','C', "delete_char",		PADM|1,	SMG$K_DELETE_CHAR )		/* Delete #1 chars (PG*) */
ENTRY('D','L', "delete_line",		PADM|1,	SMG$K_DELETE_LINE )		/* Delete #1 lines (PG*) */
ENTRY('D','O', "cursor_down",		PADM|1,	SMG$K_CURSOR_DOWN )		/* Move cursor down #1 lines (PG*) */
EXTRY('F','0', "key_f20",		KEY,	SMG$K_KEY_F20 )			/* Sent by function key f20 */
EXTRY('F','1', "key_f11",		KEY,	SMG$K_KEY_F11 )			/* Sent by function key f11 */
EXTRY('F','2', "key_f12",		KEY,	SMG$K_KEY_F12 )			/* Sent by function key f12 */
EXTRY('F','3', "key_f13",		KEY,	SMG$K_KEY_F13 )			/* Sent by function key f13 */
EXTRY('F','4', "key_f14",		KEY,	SMG$K_KEY_F14 )			/* Sent by function key f14 */
EXTRY('F','5', "key_f15",		KEY,	SMG$K_KEY_F15 )			/* Sent by function key f15 */
EXTRY('F','6', "key_f16",		KEY,	SMG$K_KEY_F16 )			/* Sent by function key f16 */
EXTRY('F','7', "key_f17",		KEY,	SMG$K_KEY_F17 )			/* Sent by function key f17 */
EXTRY('F','8', "key_f18",		KEY,	SMG$K_KEY_F18 )			/* Sent by function key f18 */
EXTRY('F','9', "key_f19",		KEY,	SMG$K_KEY_F19 )			/* Sent by function key f19 */
EXTRY('F','A', "key_f1",		KEY,	SMG$K_KEY_F1 )			/* Sent by function key f1 */
EXTRY('F','B', "key_f2",		KEY,	SMG$K_KEY_F2 )			/* Sent by function key f2 */
EXTRY('F','C', "key_f3",		KEY,	SMG$K_KEY_F3 )			/* Sent by function key f3 */
EXTRY('F','D', "key_f4",		KEY,	SMG$K_KEY_F4 )			/* Sent by function key f4 */
ENTRY('I','C', "insert_char",		PADM|1,	SMG$K_INSERT_CHAR )		/* Insert #1 blank chars (PG*) */
ENTRY('K','1', "key_7",			KEY,	SMG$K_KEY_7 )			/* Upper left of keypad */
ENTRY('K','2', "key_5",			KEY,	SMG$K_KEY_5 )			/* Center of keypad */
ENTRY('K','3', "key_9",			KEY,	SMG$K_KEY_9 )			/* Upper right of keypad */
ENTRY('K','4', "key_1",			KEY,	SMG$K_KEY_1 )			/* Lower left of keypad */
ENTRY('K','5', "key_3",			KEY,	SMG$K_KEY_3 )			/* Lower right of keypad */
EXTRY('L','0', "label_f20",		0,	SMG$K_LABEL_F20 )		/* Labels on function key f10 if not f10 */
EXTRY('L','1', "label_f11",		0,	SMG$K_LABEL_F11 )		/* Labels on function key f11 if not f11 */
EXTRY('L','2', "label_f12",		0,	SMG$K_LABEL_F12 )		/* Labels on function key f12 if not f12 */
EXTRY('L','3', "label_f13",		0,	SMG$K_LABEL_F13 )		/* Labels on function key f13 if not f13 */
EXTRY('L','4', "label_f14",		0,	SMG$K_LABEL_F14 )		/* Labels on function key f14 if not f14 */
EXTRY('L','5', "label_f15",		0,	SMG$K_LABEL_F15 )		/* Labels on function key f15 if not f15 */
EXTRY('L','6', "label_f16",		0,	SMG$K_LABEL_F16 )		/* Labels on function key f16 if not f16 */
EXTRY('L','7', "label_f17",		0,	SMG$K_LABEL_F17 )		/* Labels on function key f17 if not f17 */
EXTRY('L','8', "label_f18",		0,	SMG$K_LABEL_F18 )		/* Labels on function key f18 if not f18 */
EXTRY('L','9', "label_f19",		0,	SMG$K_LABEL_F19 )		/* Labels on function key f19 if not f19 */
ENTRY('L','E', "cursor_left",		PAD|1,	SMG$K_CURSOR_LEFT )		/* Move cursor left #1 spaces (PG) */
EXTRY('R','A', "end_am_mode",		0,	SMG$K_END_AUTOWRAP_MODE )	/* Turn off automatic margins */
ENTRY('R','I', "cursor_right",		PAD|1,	SMG$K_CURSOR_RIGHT )		/* Move cursor right #1 spaces (PG) */
EXTRY('S','A', "begin_am_mode",		0,	SMG$K_BEGIN_AUTOWRAP_MODE )	/* Turn on automatic margins */
ENTRY('S','F', "scroll_forward",	PAD|1,	SMG$K_SCROLL_FORWARD )		/* Scroll forward #1 lines (PG) */
EXTRY('S','P', "request_cursor_position", 0,	SMG$K_REQUEST_CURSOR_POSITION )	/* request cursor position */
ENTRY('S','R', "scroll_reverse",	PAD|1,	SMG$K_SCROLL_REVERSE )		/* Scroll backward #1 lines (PG) */
ENTRY('U','P', "cursor_up",		PADM|1,	SMG$K_CURSOR_UP )		/* Move cursor up #1 lines (PG*) */
ENTRY('a','e', "end_alternate_char",	PAD,	SMG$K_END_ALTERNATE_CHAR )	/* End alternate character set (P) */
ENTRY('a','l', "insert_line",		PADM,	SMG$K_INSERT_LINE )		/* Add new blank line (P*) */
ENTRY('a','s', "begin_alternate_char",	PAD,	SMG$K_BEGIN_ALTERNATE_CHAR )	/* Start alternate character set (P) */
/* ENTRY('b','l', "bel",		PAD,	bell )				/* Audible signal (bell) (P) */
/* ENTRY('b','t', "cbt",		0,	back_tab )			/* Back tab (P) */
EXTRY('c','b', "erase_line_to_cursor",	PAD,	SMG$K_ERASE_LINE_TO_CURSOR )	/* Clear to beginning of line, inclusive */
ENTRY('c','d', "erase_to_end_display",	PADM,	SMG$K_ERASE_TO_END_DISPLAY )	/* Clear to end of display (P*) */
ENTRY('c','e', "erase_to_end_line",	PAD,	SMG$K_ERASE_TO_END_LINE )	/* Clear to end of line (P) */
/* ENTRY('c','h', "hpa",		PAD|1,	column_address )		/* Set cursor column (PG) */
ENTRY('c','l', "erase_whole_display",	PADM,	SMG$K_ERASE_WHOLE_DISPLAY )	/* Clear screen and home cursor (P*) */
ENTRY('c','m', "set_cursor_abs",	PAD|2,	SMG$K_SET_CURSOR_ABS )		/* Screen rel. cursor motion row #1 col #2 (PG) */
/* ENTRY('c','r', "cr",			PAD,	carriage_return )		/* Carriage return (P) */
ENTRY('c','s', "set_scroll_region",	PAD|2,	SMG$K_SET_SCROLL_REGION )	/* change to lines #1 through #2 (vt100) (PG) */
/* ENTRY('c','t', "tbc",		PAD,	clear_all_tabs )		/* Clear all tab stops (P) */
/* ENTRY('c','v', "vpa",		PAD|1,	row_address )			/* Vertical position absolute (set row) (PG) */
EXTRY('d','0', "black_screen",		0,	SMG$K_BLACK_SCREEN )		/* set background color (black). */
EXTRY('d','1', "red_screen",		0,	SMG$K_RED_SCREEN )		/* set background color (red). */
EXTRY('d','2', "green_screen",		0,	SMG$K_GREEN_SCREEN )		/* set background color (green). */
EXTRY('d','3', "yellow_screen",		0,	SMG$K_YELLOW_SCREEN )		/* set background color (yellow). */
EXTRY('d','4', "blue_screen",		0,	SMG$K_BLUE_SCREEN )		/* set background color (blue). */
EXTRY('d','5', "magenta_screen",	0,	SMG$K_MAGENTA_SCREEN )		/* set background color (magenta). */
EXTRY('d','6', "cyan_screen",		0,	SMG$K_CYAN_SCREEN )		/* set background color (cyan). */
EXTRY('d','7', "white_screen",		0,	SMG$K_WHITE_SCREEN )		/* set background color (white). */
EXTRY('d','8', "user1_screen",		0,	SMG$K_USER1_SCREEN )		/* set background color (?light gray?). */
EXTRY('d','9', "user2_screen",		0,	SMG$K_USER2_SCREEN )		/* set background color (?dark gray?). */
ENTRY('d','c', "delete_char",		PADM,	SMG$K_DELETE_CHAR )		/* Delete character (P*) */
ENTRY('d','l', "delete_line",		PADM,	SMG$K_DELETE_LINE )		/* Delete line (P*) */
ENTRY('d','m', "begin_delete_mode",	0,	SMG$K_BEGIN_DELETE_MODE )	/* Delete mode (enter) */
ENTRY('d','o', "cursor_down",		0,	SMG$K_CURSOR_DOWN )		/* Down one line */
/* ENTRY('d','s', "dsl",		0,	dis_status_line )		/* Disable status line */
/* ENTRY('e','c', "ech",		PAD|1,	erase_chars )			/* Erase #1 characters (PG) */
ENTRY('e','d', "end_delete_mode",	0,	SMG$K_END_DELETE_MODE )		/* End delete mode */
ENTRY('e','i', "end_insert_mode",	0,	SMG$K_END_INSERT_MODE )		/* End insert mode */
/* ENTRY('f','f', "ff",			PADM,	form_feed )			/* Hardcopy terminal page eject (P*) */
ENTRY('f','s', "end_status_line",	0,	SMG$K_END_STATUS_LINE )		/* Return from status line */
/* ENTRY('h','d', "hd",			0,	down_half_line )		/* Half-line down (forward 1/2 linefeed) */
ENTRY('h','o', "home",			PAD,	SMG$K_HOME )			/* Home cursor (if no cup) */
/* ENTRY('h','u', "hu",			0,	up_half_line )			/* Half-line up (reverse 1/2 linefeed) */
/* ENTRY('i','1', "is1",		0,	init_1string )			/* Terminal initialization string */
/* ENTRY('i','2', "is3",		0,	init_3string )			/* Terminal initialization string */
/* ENTRY('i','P', "iprog",		0,	init_prog )			/* Path name of program for init */
ENTRY('i','c', "insert_char",		PAD,	SMG$K_INSERT_CHAR )		/* Insert character (P) */
/* ENTRY('i','f', "if",			0,	init_file )			/* Name of file containing is */
ENTRY('i','m', "begin_insert_mode",	0,	SMG$K_BEGIN_INSERT_MODE )	/* Insert mode (enter); */
ENTRY('i','p', "insert_pad",		PADM,	SMG$K_INSERT_PAD )		/* Insert pad after character inserted (P*) */
ENTRY('i','s', "init_string",		0,	SMG$K_INIT_STRING )		/* Terminal initialization string */
ENTRY('k','0', "key_0",			KEY,	SMG$K_KEY_0 )			/* Sent by function key f0 */
ENTRY('k','1', "key_pf1",		KEY,	SMG$K_KEY_PF1 )			/* Sent by function key f1 */
ENTRY('k','2', "key_pf2",		KEY,	SMG$K_KEY_PF2 )			/* Sent by function key f2 */
ENTRY('k','3', "key_pf3",		KEY,	SMG$K_KEY_PF3 )			/* Sent by function key f3 */
ENTRY('k','4', "key_pf4",		KEY,	SMG$K_KEY_PF4 )			/* Sent by function key f4 */
ENTRY('k','5', "key_f5",		KEY,	SMG$K_KEY_F5 )			/* Sent by function key f5 */
ENTRY('k','6', "key_f6",		KEY,	SMG$K_KEY_F6 )			/* Sent by function key f6 */
ENTRY('k','7', "key_f7",		KEY,	SMG$K_KEY_F7 )			/* Sent by function key f7 */
ENTRY('k','8', "key_f8",		KEY,	SMG$K_KEY_F8 )			/* Sent by function key f8 */
ENTRY('k','9', "key_f9",		KEY,	SMG$K_KEY_F9 )			/* Sent by function key f9 */
ENTRY('k',';', "key_f10",		KEY,	SMG$K_KEY_F10 )			/* Sent by function key f10 */
ENTRY('k','A', "key_enter",		KEY,	SMG$K_KEY_ENTER )		/* Sent by insert line */
/* ENTRY('k','C', "kclr",		0,	key_clear )			/* Sent by clear screen or erase key */
ENTRY('k','D', "key_e3",		KEY,	SMG$K_KEY_E3 )			/* Sent by delete character key */
ENTRY('k','E', "key_e5",		KEY,	SMG$K_KEY_E5 )			/* Sent by clear-to-end-of-line key */
ENTRY('k','F', "key_minus",		KEY,	SMG$K_KEY_MINUS )		/* Sent by scroll-forward/down key */
#ifdef SMG$K_KEY_END
ENTRY('k','H', "key_end",		KEY,	SMG$K_KEY_END )			/* Sent by home-down key */
#endif
ENTRY('k','I', "key_e2",		KEY,	SMG$K_KEY_E2 )			/* Sent by ins char/enter ins mode key */
/* ENTRY('k','L', "kdl1",		0,	key_dl )			/* Sent by delete line key */
/* ENTRY('k','M', "krmir",		0,	key_eic )			/* Sent by rmir or smir in insert mode */
ENTRY('k','N', "key_2",			KEY,	SMG$K_KEY_2 )			/* Sent by next-page key */
ENTRY('k','P', "key_8",			KEY,	SMG$K_KEY_8 )			/* Sent by previous-page key */
ENTRY('k','R', "key_comma",		KEY,	SMG$K_KEY_COMMA )		/* Sent by scroll-backward/up key */
ENTRY('k','S', "key_e6",		KEY,	SMG$K_KEY_E6 )			/* Sent by clear-to-end-of-screen key */
ENTRY('k','T', "key_6",			KEY,	SMG$K_KEY_6 )			/* Sent by set-tab key */
EXTRY('k','U', "key_e4",		KEY,	SMG$K_KEY_E4 )			/* Select key */
ENTRY('k','a', "key_period",		KEY,	SMG$K_KEY_PERIOD )		/* Sent by clear-all-tabs key */
ENTRY('k','b', "key_backspace",		KEY,	SMG$K_KEY_BACKSPACE )		/* Sent by backspace key */
ENTRY('k','d', "key_down_arrow",	KEY,	SMG$K_KEY_DOWN_ARROW )		/* Sent by terminal down arrow key */
ENTRY('k','e', "set_numeric_keypad",	0,	SMG$K_SET_NUMERIC_KEYPAD )	/* Out of "keypad transmit" mode */
#ifdef SMG$K_KEY_HOME
ENTRY('k','h', "key_home",		KEY,	SMG$K_KEY_HOME )		/* Sent by home key */
#endif
/* EXTRY('k','i', "key_f16",		KEY,	SMG$K_KEY_F16 )			/* Do request key */
ENTRY('k','l', "key_left_arrow",	KEY,	SMG$K_KEY_LEFT_ARROW )		/* Sent by terminal left arrow key */
/* EXTRY('k','q', "key_f15",		KEY,	SMG$K_KEY_F15 )			/* Help key */
ENTRY('k','r', "key_right_arrow",	KEY,	SMG$K_KEY_RIGHT_ARROW )		/* Sent by terminal right arrow key */
ENTRY('k','s', "set_application_keypad",0,	SMG$K_SET_APPLICATION_KEYPAD )	/* Put terminal in "keypad transmit" mode */
ENTRY('k','t', "key_4",			KEY,	SMG$K_KEY_4 )			/* Sent by clear-tab key */
ENTRY('k','u', "key_up_arrow",		KEY,	SMG$K_KEY_UP_ARROW )		/* Sent by terminal up arrow key */
/* ENTRY('l','0', "label_f0",		0,	lab_f0 )			/* Labels on function key f0 if not f0 */
ENTRY('l','1', "label_f1",		0,	SMG$K_LABEL_F1 )		/* Labels on function key f1 if not f1 */
ENTRY('l','2', "label_f2",		0,	SMG$K_LABEL_F2 )		/* Labels on function key f2 if not f2 */
ENTRY('l','3', "label_f3",		0,	SMG$K_LABEL_F3 )		/* Labels on function key f3 if not f3 */
ENTRY('l','4', "label_f4",		0,	SMG$K_LABEL_F4 )		/* Labels on function key f4 if not f4 */
ENTRY('l','5', "label_f5",		0,	SMG$K_LABEL_F5 )		/* Labels on function key f5 if not f5 */
ENTRY('l','6', "label_f6",		0,	SMG$K_LABEL_F6 )		/* Labels on function key f6 if not f6 */
ENTRY('l','7', "label_f7",		0,	SMG$K_LABEL_F7 )		/* Labels on function key f7 if not f7 */
ENTRY('l','8', "label_f8",		0,	SMG$K_LABEL_F8 )		/* Labels on function key f8 if not f8 */
ENTRY('l','9', "label_f9",		0,	SMG$K_LABEL_F9 )		/* Labels on function key f9 if not f9 */
ENTRY('l','a', "label_f10",		0,	SMG$K_LABEL_F10 )		/* Labels on function key f10 if not f10 */
ENTRY('l','e', "cursor_left",		PAD,	SMG$K_CURSOR_LEFT )		/* Move cursor left one space */
/* ENTRY('l','l', "ll",			0,	cursor_to_ll )			/* Last line, first column (if no cup) */
ENTRY('m','b', "begin_blink",		0,	SMG$K_BEGIN_BLINK )		/* Turn on blinking */
ENTRY('m','d', "begin_bold",		0,	SMG$K_BEGIN_BOLD )		/* Turn on bold (extra bright) mode */
ENTRY('m','e', "begin_normal_rendition",0,	SMG$K_BEGIN_NORMAL_RENDITION )	/* Turn off all attributes */
/* ENTRY('m','h', "dim",		0,	enter_dim_mode )		/* Turn on half-bright mode */
/* ENTRY('m','k', "invis",		0,	enter_secure_mode )		/* Turn on blank mode (chars invisible) */
/* ENTRY('m','m', "smm",		0,	meta_on )			/* Turn on "meta mode" (8th bit) */
/* ENTRY('m','o', "rmm",		0,	meta_off )			/* Turn off "meta mode" */
/* ENTRY('m','p', "prot",		0,	enter_protected_mode )		/* Turn on protected mode */
ENTRY('m','r', "begin_reverse",		0,	SMG$K_BEGIN_REVERSE )		/* Turn on reverse video mode */
ENTRY('n','d', "cursor_right",		0,	SMG$K_CURSOR_RIGHT )		/* Non-destructive space (cursor right) */
ENTRY('n','w', "cursor_next_line",	PAD,	SMG$K_CURSOR_NEXT_LINE )	/* Newline (behaves like cr followed by lf) */
/* ENTRY('p','O', "mc5p",		1,	prtr_non )			/* Turn on the printer for #1 bytes */
ENTRY('p','c', "pad_char",		0,	SMG$K_PAD_CHAR )		/* Pad character (rather than null) */
ENTRY('p','f', "end_autoprint_mode",	0,	SMG$K_END_AUTOPRINT_MODE )	/* Turn off the printer */
/* ENTRY('p','k', "pfkey",		2,	pkey_key )			/* Prog funct key #1 to type string #2 */
/* ENTRY('p','l', "pfloc",		2,	pkey_local )			/* Prog funct key #1 to execute string #2 */
ENTRY('p','o', "begin_autoprint_mode",	0,	SMG$K_BEGIN_AUTOPRINT_MODE )	/* Turn on the printer */
ENTRY('p','s', "print_screen",		0,	SMG$K_PRINT_SCREEN )		/* Print contents of the screen */
/* ENTRY('p','x', "pfx",		2,	pkey_xmit )			/* Prog funct key #1 to xmit string #2 */
/* ENTRY('r','1', "rs1",		0,	reset_1string )			/* Reset terminal completely to sane modes. */
/* ENTRY('r','2', "rs2",		0,	reset_2string )			/* Reset terminal completely to sane modes. */
/* ENTRY('r','3', "rs3",		0,	reset_3string )			/* Reset terminal completely to sane modes. */
ENTRY('r','c', "restore_cursor",	0,	SMG$K_RESTORE_CURSOR )		/* Restore cursor to position of last sc */
/* ENTRY('r','f', "rf",			0,	reset_file )			/* Name of file containing reset string */
/* ENTRY('r','p', "rep",		PADM|2,	repeat_char )			/* Repeat char #1 #2 times. (PG*) */
/* ENTRY('s','a', "sgr",		PAD|9,	set_attributes )		/* Define the video attributes (PG9) */
ENTRY('s','c', "save_cursor",		PAD,	SMG$K_SAVE_CURSOR )		/* Save cursor position (P) */
ENTRY('s','e', "end_reverse",		0,	SMG$K_END_REVERSE )		/* End stand out mode */
ENTRY('s','f', "scroll_forward",	PAD,	SMG$K_SCROLL_FORWARD )		/* Scroll text up (P) */
ENTRY('s','o', "begin_reverse",		0,	SMG$K_BEGIN_REVERSE )		/* Begin stand out mode */
ENTRY('s','r', "scroll_reverse",	PAD,	SMG$K_SCROLL_REVERSE )		/* Scroll text down (P) */
ENTRY('s','t', "set_tab",		0,	SMG$K_SET_TAB )			/* Set a tab in all rows, current column */
ENTRY('t','a', "tab_char",		0,	SMG$K_TAB_CHAR )		/* Tab to next 8 space hardware tab stop */
/* ENTRY('t','e', "rmcup",		0,	end_ca_mode )			/* String to end programs that use cup */
/* ENTRY('t','i', "smcup",		0,	enter_ca_mode )			/* String to begin programs that use  cup */
ENTRY('t','s', "begin_status_line",	1,	SMG$K_BEGIN_STATUS_LINE )	/* Go to status line, column #1 */
ENTRY('u','c', "underline_char",	0,	SMG$K_UNDERLINE_CHAR )		/* Underscore one char and move past it */
ENTRY('u','e', "end_underscore",	0,	SMG$K_END_UNDERSCORE )		/* End underscore mode */
ENTRY('u','p', "cursor_up",		0,	SMG$K_CURSOR_UP )		/* Upline (cursor up) */
ENTRY('u','s', "begin_underscore",	0,	SMG$K_BEGIN_UNDERSCORE )	/* Start underscore mode */
/* ENTRY('v','b', "flash",		0,	flash_screen )			/* Visible bell (may not move cursor) */
ENTRY('v','e', NULL,			0,	SMG$K_SET_CURSOR_ON )		/* Make cursor appear normal (undo vs/vi) */
ENTRY('v','i', "set_cursor_off",	0,	SMG$K_SET_CURSOR_OFF )		/* Make cursor invisible */
ENTRY('v','s', "set_cursor_on",		0,	SMG$K_SET_CURSOR_ON )		/* Make cursor very visible */
/* ENTRY('w','i', "wind",		4,	set_window )			/* Current window is lines #1-#2 cols #3-#4 */
EXTRY('z','C', "width_wide",		0,	SMG$K_WIDTH_WIDE )		/* Set screen to wide width. */
EXTRY('z','c', "width_narrow",		0,	SMG$K_WIDTH_NARROW )		/* Set screen to narrow width. */
  {0}	/* Zero-terminate (since not all compilers can handle trailing `,') */
};
#endif /* vms */
/*======================================================================*/
/* #module "vms-tcap.c"							*/
/*======================================================================*/
#if vms

#ifdef RCS_ID
static const char RCSid[] =
	"$Id: tsmgcap.c,v 1.3 1993/07/03 00:52:43 tom Exp tom $";
#endif

int	_termtable;
#ifdef VMS_TERMCAP
int	_termcap;
#endif
struct termchar	_termchar;

static int
_smg_tgetnum(smg_id)
{
	short	options = smg_id >> SMG_SHIFT;
	int	result = -1;

	if (smg_id &= SMG_MASK) {
#   ifndef JOVE	/* special cases: use actual tt rows/cols/auto_margin */
		if (smg_id == SMG$K_ROWS && _termchar.t_page)
			return _termchar.t_page;
		if (smg_id == SMG$K_COLUMNS && _termchar.t_width)
			return _termchar.t_width;
#   endif
		if (smg_id == SMG$K_AUTO_MARGIN)
			return (_termchar.t_mode & TT$M_WRAP) != 0;
		if (smg$get_numeric_data(&_termtable, &smg_id,
					 &result) & STS$M_SUCCESS) {
			if (options == NOT)
				result = !result;
			else
				result += options;
		}
	}
	return result;
}

static char *
_smg_tgetstr(smg_id, pp)
char	**pp;
{
	int	nparam = (smg_id >> SMG_SHIFT)/* & ~(PAD|PADM|KEY) */;
	char	*result = NULL;
	int	real_id;

	if (real_id = (smg_id & SMG_MASK)) {
		char	resultbuf[100];	/* rather arbitrary, I admit */
		int	size = sizeof resultbuf - 1;	
			len;

		if ((smg$get_term_data(&_termtable, &real_id, 
				       &size, &len,
				       (pp) ? (*pp) : resultbuf) & STS$M_SUCCESS) &&
		    (len > 0)) {
			/* special case: a valid SMG capability taking
			   variables is returned as itself. */
			if (nparam)
				return (char *) smg_id;

			if (pp) {
				result = (*pp);
				(*pp) += len;
				*(*pp)++ = '\0';
			}
			else if (result = malloc(len + 1)) {
				resultbuf[len] = '\0';
				strcpy(result, resultbuf);
			}
		}
	}
	return result;
}

static int
_smg_tgetent(buf, name)
char	*buf;
char	*name;
{
	int		result = -1;

	_termchar.t_width = _termchar.t_page = _termchar.t_mode = 0;
	_termtable = 0;

	/* first, try to initialize by type (assuming that the terminal
	   you want is connected to stdin). If that fails, try to open
	   it by name (if a name exists).  {The reason for not doing so in
	   the first place is that `getenv("TERM")' that usually supplies
	   the name delivers a made-up terminal name which is unfortunately
	   not recognized by `smg$init_term_table'. (so much for system 
           integration...)}.
	   If `name' is as yet unknown, return the actual terminal name. */
    {
	short		iochan;
	int		st;
	struct iosb {			/* I/O status block		*/
		unsigned short	i_status,	/* condition code	*/
				i_count;	/* transfer count	*/
		unsigned long	i_info;		/* device information	*/
	} iosb;
	$DESCRIPTOR(sys_input, "SYS$INPUT:");

	/* assign a channel for QIOW */
	if ((sys$assign(&sys_input, &iochan, 0, 0) & STS$M_SUCCESS) &&

	    /* get terminal characteristics */
	    (st = sys$qiow(0,			/* wait on event flag 0	*/
			   iochan,		/* channel to terminal	*/
			   IO$_SENSEMODE,	/* command code		*/
			   &iosb,		/* status of operation	*/
			   0,0,			/* no AST		*/
			   &_termchar,		/* result buffer	*/
			   sizeof _termchar,	/* buffer size		*/
			   0,0,0,0),		/* unused		*/

	     /* deassign the channel (and check status) */
	     (sys$dassgn(iochan) & STS$M_SUCCESS) &&
	     (st & STS$M_SUCCESS) &&
	     (iosb.i_status & STS$M_SUCCESS))) {

		/* init termtable by type, and get actual terminal name	*/
		struct { short length; char body[254]; } vname;
		struct dsc$descriptor_vs vnamedesc = {
			sizeof vname.body - 1, 
			DSC$K_DTYPE_VT, DSC$K_CLASS_VS, &vname
		};

		if (smg$init_term_table_by_type(&_termchar.t_type, &_termtable,
						&vnamedesc) & STS$M_SUCCESS) {
			vname.body[vname.length] = '\0';
			if (*name == '\0')
				strcpy(name, vname.body);

			return 1;
		}
		result = 0;
	}
    }
    {
	struct dsc$descriptor termname = {
		strlen(name), DSC$K_DTYPE_T, DSC$K_CLASS_S, name
	};
	if (smg$init_term_table(&termname, &_termtable) & STS$M_SUCCESS)
		result = 1;
    }
	return result;
}

/*
 * do a binary search for capability `id' in the table.
 * (assumes table is lexically ordered on id)
 */
static int
_smg_tlookup(id, table, size)
const char	*id;
const Where	*table;
int		size;
{
	register Where	*med_p;
	register int	top = 0,
			end = size,
			med;
	register short	key = ident(id[0],id[1]);

	while (top < end) {
		med_p = &table[med = (top + end) >> 1];
		if (key < med_p->tcp_id) {
			end = med;
			continue;
		}
		if (key > med_p->tcp_id) {
			top = med + 1;
			continue;
		}
		/* Gotcha! */
		DPRINTF(("[%.2s->%d]=", (char *)&med_p->tcp_id, med_p->smg_id));
		return med_p->smg_id;
	}
	DPRINTF(("(nope)\n"));
	return 0;
}

char *
tgoto(cm, col, line)
const char	*cm;
{
	if (cm <= (const char *) SMG_MAX) {	
		/* an SMG capability; use SMG to instantiate this.
		   Large character buffer to allow expansion of
		   non-parameterized capabilities. */
		static char	result[256];
		static int	size = sizeof result - 1;
		int		args[1 + 2];
		int		len;
		int		smg_id = (int) cm & SMG_MASK;

		/* take care here since SMG expects 1-based line/column
		   numbers for cursor- and scroll-region capabilities,
		   where the tgoto uses 0-based numbers,
		   whereas repeat counts (for other capabilities)
		   should not be changed... */
		args[0] = (int) cm >> SMG_SHIFT;
		if (args[0] < 2)
			args[1] = line;
		else {
			args[1] = line + 1;
			args[2] = col + 1;
		}
		if ((smg$get_term_data(&_termtable, &smg_id, &size, &len,
				       result, args) & STS$M_SUCCESS) &&
		    (len > 0)) {
			result[len] = '\0';
			return result;
		}
	}
#ifdef tgoto
#   undef tgoto
	else
		/* use termcap */
		return tgoto(cm, col, line);
#endif
	return "OOPS";
}

int
tgetflag(id)
const char *id;
{
	/* #insert "vms-tflagtab.h" */
	int	flag;
#if TERMCAP_FIRST
#   undef tgetflag
	if (_termcap > 0 && (flag = tgetflag(id)) >= 0)
		return flag;
#endif
	flag = _smg_tgetnum(_smg_tlookup(id, FlagTab, TABLESIZE(FlagTab)));
	if (flag < 0)
#ifdef tgetflag
#   undef tgetflag
		if (_termcap > 0)
			flag = tgetflag(id);
		else
#endif
			flag = 0;
	return flag;
}

int
tgetnum(id)
const char *id;
{
	/* #insert "vms-tnumtab.h" */
	int	num;
#if TERMCAP_FIRST
#   undef tgetnum
	if (_termcap > 0 && (num = tgetnum(id)) >= 0)
		return num;
#endif
	num = _smg_tgetnum(_smg_tlookup(id, NumTab, TABLESIZE(NumTab)));
#ifdef tgetnum
#   undef tgetnum
	if (num < 0)
		if (_termcap > 0)
			num = tgetnum(id);
#endif
	return num;
}

char *
tgetstr(id, pp)
const char *id;
char **pp;
{
	/* #insert "vms-tstrtab.h" */
	char	*str;
#if TERMCAP_FIRST
#   undef tgetstr
	if (_termcap > 0 && (str = tgetstr(id, pp)))
		return str;
#endif
	str = _smg_tgetstr(_smg_tlookup(id, StrTab, TABLESIZE(StrTab)), pp);
#ifdef tgetstr
#   undef tgetstr
	if (str == NULL)
		if (_termcap > 0)
			str = tgetstr(id, pp);
#endif
	return str;
}

int
tgetent(buf, name)
char	*buf;
const char *name;
{
	char	namebuf[256];
	int	result;

	if (name == NULL || *name == '\0')
		*(char *)(name = namebuf) = '\0';
	result = _smg_tgetent(buf, (char *) name);
#ifdef tgetent
#   undef tgetent
	_termcap = result = tgetent(buf, name);
#endif
	return (_termtable) ? 1 : result;
}
#endif /* vms */
/*======================================================================*/
