OpenVMS Source Code Demos
DEC_DEVICE_CONTROLS
//==============================================================================================================================
// title : dec_device_controls.c
// Author : Neil Rieck ( https://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
//======================================================================