OpenVMS Source-Code Demos

DEC_DEVICE_CONTROLS

//==============================================================================================================================
// title     :	dec_device_controls.c
// Author    :	Neil Rieck                ( http://neilrieck.net/ )
//		Waterloo, Ontario, Canada.
// created   :	2015-04-19
// references:	https://en.wikipedia.org/wiki/ANSI_escape_code
//		http://terminals.classiccmp.org/wiki/index.php/DEC_VT100
//		http://terminals.classiccmp.org/wiki/index.php/DEC_VT102
//		http://www.vt100.net/docs/vt220-rm/ (programmer reference)
//		http://www.vt100.net/docs/vt3xx-gp/ (graphics programming)
//		http://web.mit.edu/dosathena/doc/www/ek-vt520-rm.pdf
//		http://invisible-island.net/xterm/xterm.faq.html
// history   :
// ver who when     what
// --- --- -------- ------------------------------------------------------------------------------------------------------------
// 100 NSR 19870501 original (device_controls.inc) for VAX BASIC-3.0 on VMS-4.2
// 200 NSR 20150418 converted to dec_device_controls.c for DEC-C on OpenVMS-8.4
//     NSR 20150419 began adding codes to manipulate color
//     NSR 20150425 more color hacks
//     NSR 20150426 cleanup
//     NSR 20150502 cleanup for publication on the web (this is still an unfinished document; a work in progress)
//==============================================================================================================================
// Introduction (1987): The formal way to control VT terminals from high-level langauges (eg. COBOL, FORTRAN, BASIC, C) is to
// perform SMG$ calls ("SMGDEF" in Starlet) which will issue the correct escape sequences to your properly indentified terminal
// via your terminal driver. But if you find yourself on an overloaded or unpowered VAX then it might be better to just send
// escape sequences directly to your process's output channel (sys$output). This choice is easier if you know that everyone on
// your system is running VT220 (or higher) terminals and will never be stupid enough to run your software from an LA120.
//
// Overview (1987): Peripheral hardware from DEC (Digital Equipment Corporation) can be controlled by "escape sequences" which
// always begin with the ESCAPE character (ascii-27) and usually followed by left-square-bracket.
//
// Here are a few example "escape secquences" for a VT100 terminal:
//	1) clear the screen	ESC [ 2 J	(4 characters)
//	2) home the cursor	ESC [ 1 ; 1 H	(6 characters)
//	3) save cursor position	ESC 7		(2 characters)
//	4) restore cursor pos	ESC 8		(2 characters)
//------------------------------------------------------------------------------------------------------------------------------
// Comment (2015): I have no idea why "C" programmers refer to chracters like these ('\a','\r','\n' ) as escape characters since
// they do not involve ascii-27.
//==============================================================================================================================
// Hardware Overview:
// 1) VT52  was DEC's first popular terminal but it had a limited set of mostly proprietary control codes
// 2) VT100 added many more codes (both ANSI and proprietary) and four personal function keys (PF1 to PF4) top of the numeric
//    keypad. Limited memory restricted displays to 24x80 or 14x132 with simple per-character display options like reverse
//    video. A small board ("advanced video option") would convert your VT100 into a pseudo-VT102 which now supports 24x132 as
//    well as other per-character display options like "underlining" and "double intensity"
// 3) VT220 added: F keys (F1-F14) above the numeric keys; an application key pad between the keyboard and numeric keypad;
//    RegIS graphics in the VT240 and color was availble in the VT241
// 4) VT340 provided 16-color simultaneous support (of 4096) via palettes while VT525 provided 256-color support
// 5) most emulators today are based upon xterm (which was developed for MIT's x-windows platform)
// 6) an LA50 printer was usually connected to a port on the VT terminal to do either slave or pass-through printing
//==============================================================================================================================
// Additional Information:
// This side of y2k, there are many places where VT technology is still being used (telcos, utilities, nuclear reactors, etc).
// Those businesses will always use hardware (still manufactured by Boundless). Professional developers will probably test with
// terminal emulators like Attachmate's "Reflection for UNIX and OpenVMS" (the gold standard in VT emulation) while hobbyists
// will probably use free stuff like Tera Term ( http://logmett.com/freeware/TeraTerm.php ) or PuTTY.
//==============================================================================================================================
//
//==============================================================
//	<<< VT Device Control Strings >>>
//==============================================================
#define ESCAPE		"\x1b"					// ascii-27
#define BELL		"\x07"					// ascii-7 (same as '\a' in C/C++)
#define ESCAPE8		"\x9b"					// ascii-155 (128+27)
//
#define CSI		ESCAPE "["				// Control Sequence Introducer (7-bit)
#define CSI8		ESCAPE8					// Control Sequence Introducer (8-bit)
#define DSC		ESCAPE "P"				// Device Control String
#define ST		ESCAPE "\\"				// String Terminator
//
//	printer port control (page 28+29, 'VT220 Programmer Pocket Guide')
//
const char VT$PrinterOn[]		= CSI "5i"	;	// controller on
const char VT$PrinterOff[]		= CSI "4i"	;	// controller off
const char VT$DualOutOn[]		= CSI "?5i"	;	// auto on
const char VT$DualOutOff[]		= CSI "?4i"	;	// auto off
const char VT$ScreenPrint[]		= CSI "i"	;	// screen print
//
//	Terminal Modes (page 21, 'VT220 Programmer Pocket Guide')
//
const char VT$KeyLock[]			= CSI "2h"	;	// keyboard lock
const char VT$KeyUnLock[]		= CSI "2l"	;	// keyboard un-lock
const char VT$132[]			= CSI "?3h"	;	// 132 column
const char VT$80[]			= CSI "?3l"	;	//  80 column
const char VT$AutoWrap[]		= CSI "?7h"	;	// auto wrap
const char VT$NoAutoWrap[]		= CSI "?7l"	;	// no auto wrap
//
//	Select Graphic Rendition (page 24, 'VT220 Programmer Pocket Guide')
//
const char VT$Cursor_on[]		= CSI "?25h"	;	// text cursor on
const char VT$Cursor_off[]		= CSI "?25l"	;	// text cursor off
const char VT$Normal[]			= CSI "0m"	;	// attributes off
const char VT$Bright[]			= CSI "1m"	;	// bright
const char VT$Under[]			= CSI "4m"	;	// underline
const char VT$Flash[]			= CSI "5m"	;	// flash
const char VT$Reverse[]			= CSI "7m"	;	// reverse video
const char VT$NoBright[]		= CSI "22m"	;	// no bright
const char VT$NoUnder[]			= CSI "24m"	;	// no Underline
const char VT$NoFlash[]			= CSI "25m"	;	// no flash
const char VT$NoReverse[]		= CSI "27m"	;	// no reverse
//
// line erasing  (page 26, 'VT220 Programmer Pocket Guide')
//
const char VT$ClearEOL[]		= CSI "0K"	;	// clear to end-of-line
const char VT$ClearBOL[]		= CSI "1K"	;	// clear to beginning-of-line
const char VT$ClearLine[]		= CSI "2K"  	;	// clear whole line
//
// screen erasing (page 26, 'VT220 Programmer Pocket Guide')
//
const char VT$ClearEOS[]		= CSI "0J"	;	// clear to end-of-screen
const char VT$ClearBOS[]		= CSI "1J"	;	// clear to beginning-of-screen
const char VT$Clear[]			= CSI "2J"	;	// clear whole screen
//
// line attributes (page 25, 'VT220 Programmer Pocket Guide')
// (these escape codes do not employ left-square bracket)
//
const char VT$SingleWidth[]		= ESCAPE "#5"	;	//
const char VT$DoubleWidth[]		= ESCAPE "#6"	;	//
const char VT$DoubleHeightTop[]		= ESCAPE "#3"	;	//
const char VT$DoubleHeightBottom[]	= ESCAPE "#4"	;	//
//
// cursor positioning (page 23, 'VT220 Programmer Pocket Guide')
// (these escape codes do not employ left-square bracket)
//
const char VT$SaveCursor[]		= ESCAPE "7"	;	// save cursor position
const char VT$RestoreCursor[]		= ESCAPE "8"	;	// restore cursor position
//
// cursor motion (page 22, 'VT220 Programmer Pocket Guide')
//
const char VT$CursUp[]			= CSI "1A"	;	// one means up    by one
const char VT$CursDown[]		= CSI "1B"	;	// one means down  by one
const char VT$CursRight[]		= CSI "1C"	;	// one means right by one
const char VT$CursLeft[]		= CSI "1D"	;	// one means left  by one
//
// keypad mode (page 21, 'VT220 Programmer Pocket Guide')
// (these codes do not employ left-square bracket)
//
const char VT$KeyPadApp[]		= ESCAPE "="	;	// switch numeric keypad to app mode
const char VT$KeyPadNum[]		= ESCAPE ">"	;	// switch numeric kp back to num mode
//
//==============================================================
//	LA50 Device Control Codes
//==============================================================
//
// Printer Horizontal Pitch (page 31, 'LA50 Programmer Reference Manual')
//
const char LA$HP10[]			= CSI "0w"	;	// 10    char/inch
const char LA$HP12[]			= CSI "2w"	;	// 12    char/inch
const char LA$HP16[]			= CSI "4w"	;	// 16.5  char/inch
const char LA$HP5[]			= CSI "5w"	;	//  5    char/inch
const char LA$HP6[]			= CSI "6w"	;	//  6    char/inch
const char LA$HP8[]			= CSI "8w"  	;	//  8.25 char/inch
//
// Printer Vertical Pitch (page 33, 'LA50 Programmer Reference Manual')
//
const char LA$VP6[]			= CSI "0z"	;	//  6 char/inch
const char LA$VP12[]			= CSI "2z"	;	//  8 char/inch
const char LA$VP16[]			= CSI "3z"	;	// 12 char/inch
const char LA$VP2[]			= CSI "4z"	;	//  2 char/inch
const char LA$VP3[]			= CSI "5z"	;	//  3 char/inch
const char LA$VP4[]			= CSI "6z"	;	//  4 char/inch
//
// Select Graphic Rendition (page 39, 'LA50 Programmer Reference Manual')
//
const char LA$Normal[]			= CSI "0m"	;	// normal
const char LA$Bold[]			= CSI "1m"	;	// bold on
const char LA$Under[]			= CSI "4m"	;	// underline
const char LA$NoBold[]			= CSI "22m"	;	// no bold
const char LA$NoUnder[]			= CSI "24m"	;	// no underline
//
//==============================================================
//	common synonyms
//==============================================================
const char VT$Home[]			= CSI	"1;1H"	;	// goto to line # 1, character #1
const char VT$Error[]			= CSI	"24;1H"		// goto to line #24, character #1
					  CSI	"2K"	;	// the clear line
const char VT$SavCurErr[]		= ESCAPE "7"		// save cursor (b4 error msg)
					  CSI	"24;1H"		// goto to line #24, character #1
					  CSI	"2K"	;	// the clear line
//==============================================================================
//	color commands (new for 2015)
//==============================================================================
// notes:
// 1) Earlier terminals only supported 16 colors of 4096 (implemented in 16 color palettes)
//    a. each palette has a single foreground and backgound color
//    b. probably a good idea to avoid altering palettes 0 and 15 which deal with black and white
//	 (if you do change them then be sure to restore them before you exit)
// 2) Next came terminals which could support 256 colors
//    a. more research need here
// 3) Other weirdness from the docs:
//	CSI	= esc [		command string introducer (7-bit)
//	DSC	= esc P		Device Control String
//	ST	= esc \		String Terminator
//	CSI	= '\x9b'	command string introducer (8-bit)
// 4. This side of y2k it appears that support for UTF-8 is more imporatant than saving a byte
//    so modern programmers should not use 8-bit escape codes.
//==============================================================================
//
//	color spaces (how to interpret color data)
//
#define vtHLS		"1;"						// hue, lightness, saturation
#define vtRGB		"2;"						// red-green-blue
//
//	these are listed in many places as ANSI colors (but is this true?)
//
#define	vtBlack		"0"						//
#define vtRed		"1"						//
#define vtGreen		"2"						//
#define vtkYellow	"3"						//
#define vtBlue		"4"						//
#define vtMagenta	"5"						//
#define vtCyan		"6"						//
#define vtWhite		"7"						//
#define vtExtend	"8"						// only supported with xterm (256 colors)
#define vtDefault	"9"						// set default FG or BG
//
//	prefixes for ForeGround and BackGround
//
#define vtFG		"3"						// so 31 is FG+red   while 39 is FG+default
#define vtBG		"4"						// so 42 is BG+green while 49 is BG+default
//
//	Select Graphic Rendition
//
const char VT$Red[]		= CSI "31m";				// red foreground
const char VT$RedOnBlue[]	= CSI "31;44m";				//
const char VT$BlackOnWhite[]	= CSI "37;40m";				//
const char VT$WhiteOnBlack[]	= CSI "30;47m";				//
//
//const char VT$xterm_hack1[]	= CSI "38;5xm";				// where x = 0-255 (color index)
//const char VT$xterm_hack2[]	= CSI "38;5ym";				// where y = 2;r;g;b (where r,g,b:0-255)
//									// (remember that "2;" = vtRGB)
//
//	various experimental hacks
//
//                                        +-- palette #
//                                        | + color space = 2 (RGB)
//                                        | | red;green;blue;red;green;blue;
const char VT$SetPal7[]		= DSC "2$p7;2;255;0;0;0;0;255;";	// palette 7 hacking
const char VT$SetPal8[]		= DSC "2$p8;2;0;255;0;";		// palette 8 hacking
const char VT$SetPal9[]		= DSC "2$p9;2;0;0;255;";		// palette 9 hacking
const char VT$ReadPal[]		= CSI "2;2$u";				// palette hacking
//======================================================================