initial commit

This commit is contained in:
Diego Fernando Carrión 2024-08-10 16:57:58 +02:00
parent d8292ffd36
commit 1d97a34694
Signed by: CRThaze
GPG Key ID: 8279B79A1A7F8194
6 changed files with 1311 additions and 3 deletions

View File

@ -1,4 +1,19 @@
# vtTools
# VT Tools
A Go library for providing support for Digital Equipment
Corporation Video Terminals
VT Tools is a Go library for providing support for Digital Equipment
Corporation Video Terminals to Go programs.
**It currently only supports the DEC VT220 in 8-bit Mode.**
## Why
Go programs are written in UTF-8. This can be cause challenges when running
the compiled program on DEC Hardware Terminals which use a proprietary 8-bit
encoding which (while flexible) is only partially compatible with modern
character encoding formats.
This library aims to allow developers to write Go code (in UTF-8) which can
be run correctly on DEC Video Terminals.
It also provides *some* support for manipulating the terminal in additional ways
according to its documented spec.

564
codetable.go Normal file
View File

@ -0,0 +1,564 @@
package main
import (
"errors"
"fmt"
)
type controlRow [2]byte
type controlTable [16]controlRow
type ControlRange struct {
table controlTable
colOffset uint8
}
func (r *ControlRange) Get(col, row int) (byte, error) {
if col < int(r.colOffset) || col >= int(r.colOffset)+2 || row < 0 || row > 15 {
return byte(0), errors.New("Coordinates Out Of Bounds")
}
return glTable[row][col-int(r.colOffset)], nil
}
type graphicRow [6]byte
type graphicTable [16]graphicRow
type rangeLookup map[rune]*byte
type GraphicRange struct {
table graphicTable
set rangeLookup
colOffset uint8
}
func (r *GraphicRange) Get(col, row int) (byte, error) {
if col < int(r.colOffset) || col >= int(r.colOffset)+6 || row < 0 || row > 15 {
return byte(0), errors.New("Coordinates Out Of Bounds")
}
return r.table[row][col-int(r.colOffset)], nil
}
func (r *GraphicRange) Lookup(ru rune) *byte {
if point, ok := r.set[ru]; ok {
return point
}
return nil
}
func (r *GraphicRange) load(gOverlay *CharacterSet) {
if r.set == nil {
r.set = rangeLookup{}
}
for i, row := range gOverlay.table {
for j, graph := range row {
if graph == nil {
continue
}
r.set[*graph] = &r.table[i][j]
}
}
}
const (
// Column 0
C00R00 = 0b0000_0000 + iota
C00R01
C00R02
C00R03
C00R04
C00R05
C00R06
C00R07
C00R08
C00R09
C00R10
C00R11
C00R12
C00R13
C00R14
C00R15
// Column 1
C01R00
C01R01
C01R02
C01R03
C01R04
C01R05
C01R06
C01R07
C01R08
C01R09
C01R10
C01R11
C01R12
C01R13
C01R14
C01R15
// Column 2
C02R00
C02R01
C02R02
C02R03
C02R04
C02R05
C02R06
C02R07
C02R08
C02R09
C02R10
C02R11
C02R12
C02R13
C02R14
C02R15
// Column 3
C03R00
C03R01
C03R02
C03R03
C03R04
C03R05
C03R06
C03R07
C03R08
C03R09
C03R10
C03R11
C03R12
C03R13
C03R14
C03R15
// Column 4
C04R00
C04R01
C04R02
C04R03
C04R04
C04R05
C04R06
C04R07
C04R08
C04R09
C04R10
C04R11
C04R12
C04R13
C04R14
C04R15
// Column 5
C05R00
C05R01
C05R02
C05R03
C05R04
C05R05
C05R06
C05R07
C05R08
C05R09
C05R10
C05R11
C05R12
C05R13
C05R14
C05R15
// Column 6
C06R00
C06R01
C06R02
C06R03
C06R04
C06R05
C06R06
C06R07
C06R08
C06R09
C06R10
C06R11
C06R12
C06R13
C06R14
C06R15
// Column 7
C07R00
C07R01
C07R02
C07R03
C07R04
C07R05
C07R06
C07R07
C07R08
C07R09
C07R10
C07R11
C07R12
C07R13
C07R14
C07R15
// Column 8
C08R00
C08R01
C08R02
C08R03
C08R04
C08R05
C08R06
C08R07
C08R08
C08R09
C08R10
C08R11
C08R12
C08R13
C08R14
C08R15
// Column 9
C09R00
C09R01
C09R02
C09R03
C09R04
C09R05
C09R06
C09R07
C09R08
C09R09
C09R10
C09R11
C09R12
C09R13
C09R14
C09R15
// Column 10
C10R00
C10R01
C10R02
C10R03
C10R04
C10R05
C10R06
C10R07
C10R08
C10R09
C10R10
C10R11
C10R12
C10R13
C10R14
C10R15
// Column 11
C11R00
C11R01
C11R02
C11R03
C11R04
C11R05
C11R06
C11R07
C11R08
C11R09
C11R10
C11R11
C11R12
C11R13
C11R14
C11R15
// Column 12
C12R00
C12R01
C12R02
C12R03
C12R04
C12R05
C12R06
C12R07
C12R08
C12R09
C12R10
C12R11
C12R12
C12R13
C12R14
C12R15
// Column 13
C13R00
C13R01
C13R02
C13R03
C13R04
C13R05
C13R06
C13R07
C13R08
C13R09
C13R10
C13R11
C13R12
C13R13
C13R14
C13R15
// Column 14
C14R00
C14R01
C14R02
C14R03
C14R04
C14R05
C14R06
C14R07
C14R08
C14R09
C14R10
C14R11
C14R12
C14R13
C14R14
C14R15
// Column 15
C15R00
C15R01
C15R02
C15R03
C15R04
C15R05
C15R06
C15R07
C15R08
C15R09
C15R10
C15R11
C15R12
C15R13
C15R14
C15R15
)
const UNKNOWN = C03R15 // 0b0011_1111
const (
NUL = C00R00
SOH = C00R01
STX = C00R02
ETX = C00R03
EOT = C00R04
ENQ = C00R05
ACK = C00R06
BEL = C00R07
BS = C00R08
HT = C00R09
LF = C00R10
VT = C00R11
FF = C00R12
CR = C00R13
SO = C00R14
SI = C00R15
DLE = C01R00
DC1 = C01R01 // XON
DC2 = C01R02
DC3 = C01R03 // XOFF
DC4 = C01R04
NAK = C01R05
SYN = C01R06
ETB = C01R07
CAN = C01R08
EM = C01R09
SUB = C01R10
ESC = C01R11
FS = C01R12
GS = C01R13
RS = C01R14
US = C01R15
)
var c0Table controlTable = controlTable{
controlRow{NUL, DLE},
controlRow{SOH, DC1},
controlRow{STX, DC2},
controlRow{ETX, DC3},
controlRow{EOT, DC4},
controlRow{ENQ, NAK},
controlRow{ACK, SYN},
controlRow{BEL, ETB},
controlRow{BS, CAN},
controlRow{HT, EM},
controlRow{LF, SUB},
controlRow{VT, ESC},
controlRow{FF, FS},
controlRow{CR, GS},
controlRow{SO, RS},
controlRow{SI, US},
}
var C0 ControlRange = ControlRange{
table: c0Table,
colOffset: 0,
}
var glTable graphicTable = graphicTable{
graphicRow{C02R00, C03R00, C04R00, C05R00, C06R00, C07R00},
graphicRow{C02R01, C03R01, C04R01, C05R01, C06R01, C07R01},
graphicRow{C02R02, C03R02, C04R02, C05R02, C06R02, C07R02},
graphicRow{C02R03, C03R03, C04R03, C05R03, C06R03, C07R03},
graphicRow{C02R04, C03R04, C04R04, C05R04, C06R04, C07R04},
graphicRow{C02R05, C03R05, C04R05, C05R05, C06R05, C07R05},
graphicRow{C02R06, C03R06, C04R06, C05R06, C06R06, C07R06},
graphicRow{C02R07, C03R07, C04R07, C05R07, C06R07, C07R07},
graphicRow{C02R08, C03R08, C04R08, C05R08, C06R08, C07R08},
graphicRow{C02R09, C03R09, C04R09, C05R09, C06R09, C07R09},
graphicRow{C02R10, C03R10, C04R10, C05R10, C06R10, C07R10},
graphicRow{C02R11, C03R11, C04R11, C05R11, C06R11, C07R11},
graphicRow{C02R12, C03R12, C04R12, C05R12, C06R12, C07R12},
graphicRow{C02R13, C03R13, C04R13, C05R13, C06R13, C07R13},
graphicRow{C02R14, C03R14, C04R14, C05R14, C06R14, C07R14},
graphicRow{C02R15, C03R15, C04R15, C05R15, C06R15, C07R15},
}
var GL GraphicRange = GraphicRange{
table: glTable,
colOffset: 2,
}
const (
IND = C08R04
NEL = C08R05
SSA = C08R06
ESA = C08R07
HTS = C08R08
HTJ = C08R09
VTS = C08R10
PLD = C08R11
PLU = C08R12
RI = C08R13
SS2 = C08R14
SS3 = C08R15
DCS = C09R00
PU1 = C09R01
PU2 = C09R02
STS = C09R03
CCH = C09R04
MW = C09R05
SPA = C09R06
EPA = C09R07
CSI = C09R11
ST = C09R12
OSC = C09R13
PM = C09R14
APC = C09R15
)
var c1Table controlTable = controlTable{
controlRow{C08R00, DCS},
controlRow{C08R01, PU1},
controlRow{C08R02, PU2},
controlRow{C08R03, STS},
controlRow{IND, CCH},
controlRow{NEL, MW},
controlRow{SSA, SPA},
controlRow{ESA, EPA},
controlRow{HTS, C09R08},
controlRow{HTJ, C09R09},
controlRow{VTS, C09R10},
controlRow{PLD, CSI},
controlRow{PLU, ST},
controlRow{RI, OSC},
controlRow{SS2, PM},
controlRow{SS3, APC},
}
var C1 ControlRange = ControlRange{
table: c1Table,
colOffset: 8,
}
var grTable graphicTable = graphicTable{
graphicRow{C10R00, C11R00, C12R00, C13R00, C14R00, C15R00},
graphicRow{C10R01, C11R01, C12R01, C13R01, C14R01, C15R01},
graphicRow{C10R02, C11R02, C12R02, C13R02, C14R02, C15R02},
graphicRow{C10R03, C11R03, C12R03, C13R03, C14R03, C15R03},
graphicRow{C10R04, C11R04, C12R04, C13R04, C14R04, C15R04},
graphicRow{C10R05, C11R05, C12R05, C13R05, C14R05, C15R05},
graphicRow{C10R06, C11R06, C12R06, C13R06, C14R06, C15R06},
graphicRow{C10R07, C11R07, C12R07, C13R07, C14R07, C15R07},
graphicRow{C10R08, C11R08, C12R08, C13R08, C14R08, C15R08},
graphicRow{C10R09, C11R09, C12R09, C13R09, C14R09, C15R09},
graphicRow{C10R10, C11R10, C12R10, C13R10, C14R10, C15R10},
graphicRow{C10R11, C11R11, C12R11, C13R11, C14R11, C15R11},
graphicRow{C10R12, C11R12, C12R12, C13R12, C14R12, C15R12},
graphicRow{C10R13, C11R13, C12R13, C13R13, C14R13, C15R13},
graphicRow{C10R14, C11R14, C12R14, C13R14, C14R14, C15R14},
graphicRow{C10R15, C11R15, C12R15, C13R15, C14R15, C15R15},
}
var GR GraphicRange = GraphicRange{
table: grTable,
colOffset: 10,
}
func init() {
GL.load(DEC.MSC.ASCIIGraphic)
GR.load(DEC.MSC.SupplementalGraphic)
G0.Load(0)
G1.Load(1)
G2.Load(2)
}
// Trans takes a rune and finds the matching code point in either the GL or the GR graphics table.
// The code-point is then returned as a string.
// If no matching code-point could be found, then an error is returned.
func Trans(r rune) (string, error) {
ba := [1]byte{}
if b := GL.Lookup(r); b != nil {
ba[0] = *b
} else if b := GR.Lookup(r); b != nil {
ba[0] = *b
} else {
return "", errors.New("No translation for rune.")
}
return string(ba[:]), nil
}
// MustTrans takes a rune and calls the Trans function. if the Trans function returns an error then
// MustTrans returns the code-point for a question mark on the default graphics set (0x3F).
func MustTrans(r rune) string {
if s, err := Trans(r); err == nil {
return s
}
ba := [1]byte{UNKNOWN}
return fmt.Sprintf("%c", ba[0])
}
// SafeTrans uses an equivalency table for the given rune to determine a similiar rune that is
// present in the currently loaded character sets. It then calls MustTrans with that rune.
func SafeTrans(r rune) string {
// TODO: implement
return ""
}
// TransDynamic first calls Trans. If Trans returns an error, then it attempts to find the rune
// anywhere within the GraphicRepetoir. If it is able to find the rune, it adds the necessary
// escape sequences to temporarily load the needed character set to properly display the matching
// symbol. If none can be found, it retuns the same fall-back code-point as MustTrans.
func TransDynamic(r rune) string {
if s, err := Trans(r); err == nil {
return s
}
ba := [5]byte{}
for _, overlay := range GraphicRepetoir.gr {
if _, ok := overlay.lookup[r]; !ok {
continue
}
if *overlay.table[0][0] == r {
// TODO: load
}
}
// TODO: return UNKNOWN
return string(ba[:])
}
// SafeTrans uses an equivalency table for the given rune to determine a similiar rune that is
// present in the GraphicRepetoir. It then calls TransDynamic with that rune.
func SafeTransDynamic(r rune) string {
// TODO: implement
return ""
}

148
control.go Normal file
View File

@ -0,0 +1,148 @@
package main
// type sequence uint64
// type ControlSequence struct {
// seq sequence
// }
// func NewControlSequence(bs ...byte) (ControlSequence, error) {
// var seq sequence
// if len(bs) > 7 {
// return ControlSequence{}, errors.New("Sequence overflow.")
// }
// seq += sequence(len(bs) << 56)
// for i, b := range bs {
// seq += sequence(b << ((len(bs) - i) * 8))
// }
// return ControlSequence{seq: seq}, nil
// }
// func NewEscapeSequence(bs ...byte) (ControlSequence, error) {
// if len(bs) > 6 {
// return ControlSequence{}, errors.New("Sequence overflow.")
// }
// return NewControlSequence(append([]byte{ESC}, bs...)...)
// }
// func MustControlSequence(seq ControlSequence, err error) ControlSequence {
// if err != nil {
// panic(err)
// }
// return seq
// }
// func (seq ControlSequence) Bytes() []byte {
// var byteLen uint8 = uint8((seq.seq >> 56) & 0xFF)
// ba := make([]byte, byteLen, byteLen)
// for i := uint8(0); i < byteLen; i++ {
// ba[byteLen-uint8(1+i)] = byte(seq.seq & (0xFF << (8 * i)))
// }
// return ba
// }
// func (seq ControlSequence) String() string {
// return string(seq.Bytes()[:])
// }
type ControlSequence struct {
seq []byte
}
func NewControlSequence(bs ...byte) ControlSequence {
cs := ControlSequence{
seq: make([]byte, len(bs), len(bs)),
}
copy(cs.seq, bs)
return cs
}
func (seq ControlSequence) Bytes() []byte {
return seq.seq
}
func (seq ControlSequence) String() string {
return string(seq.Bytes()[:])
}
type ControlSequencePrefix struct {
pfx ControlSequence
}
func NewControlSequencePrefix(bs ...byte) ControlSequencePrefix {
return ControlSequencePrefix{
pfx: NewControlSequence(bs...),
}
}
func (pfx ControlSequencePrefix) Append(bs ...byte) ControlSequencePrefix {
newLen := len(pfx.pfx.seq) + len(bs)
ba := make([]byte, newLen, newLen)
copy(ba, pfx.pfx.seq)
ba = append(ba, bs...)
return ControlSequencePrefix{ControlSequence{seq: ba}}
}
func (pfx ControlSequencePrefix) With(bs ...byte) ControlSequence {
newLen := len(pfx.pfx.seq) + len(bs)
ba := make([]byte, newLen, newLen)
copy(ba, pfx.pfx.seq)
ba = append(ba, bs...)
return ControlSequence{seq: ba}
}
var (
// Prefixes
EscapeCSP = NewControlSequencePrefix(ESC)
DesignateCharSetR0CSP = EscapeCSP.Append(C02R08)
DesignateCharSetR1CSP = EscapeCSP.Append(C02R09)
DesignateCharSetR2CSP = EscapeCSP.Append(C02R10)
DesignateCharSetR3CSP = EscapeCSP.Append(C02R11)
// Complete Sequences
CS = struct {
LockShiftG0,
LockShiftG1,
LockShiftG1Right,
LockShiftG2,
LockShiftG2Right,
LockShiftG3,
LockShiftG3Right,
SingleShiftG2,
SingleShiftG3 ControlSequence
}{
// Lock Shifts
LockShiftG0: NewControlSequence(SI),
LockShiftG1: NewControlSequence(SO),
LockShiftG1Right: EscapeCSP.With(C07R14),
LockShiftG2: EscapeCSP.With(C06R14),
LockShiftG2Right: EscapeCSP.With(C07R13),
LockShiftG3: EscapeCSP.With(C06R15),
LockShiftG3Right: EscapeCSP.With(C07R12),
// Single Shifts
SingleShiftG2: NewControlSequence(SS2),
SingleShiftG3: NewControlSequence(SS3),
}
CSAbbr = struct {
LS0,
LS1,
LS1R,
LS2,
LS2R,
LS3,
LS3R,
SS2,
SS3 ControlSequence
}{
LS0: CS.LockShiftG0,
LS1: CS.LockShiftG1,
LS1R: CS.LockShiftG1Right,
LS2: CS.LockShiftG2,
LS2R: CS.LockShiftG2Right,
LS3: CS.LockShiftG3,
LS3R: CS.LockShiftG3Right,
SS2: CS.SingleShiftG2,
SS3: CS.SingleShiftG3,
}
)

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.sdf.org/CRThaze/vtTools
go 1.22.5

484
graphics.go Normal file
View File

@ -0,0 +1,484 @@
package main
import (
"errors"
"fmt"
)
type Grapheme *rune
func G(r rune) Grapheme {
return &r
}
func N(r *rune) Grapheme {
return r
}
type GraphicRow [6]Grapheme
type GraphicTable [16]GraphicRow
type lookupTable map[rune]struct{}
func (t lookupTable) Has(r rune) bool {
if _, ok := t[r]; ok {
return true
}
return false
}
func (t lookupTable) Get(r rune) *rune {
if !t.Has(r) {
return nil
}
return &r
}
type CharacterSet struct {
table GraphicTable
lookup lookupTable
dscsInter0 *byte
dscsInter1 *byte
dcscFinal byte
decdld *ControlSequence
}
func (set CharacterSet) IsDownLineLoadable() bool {
if set.decdld == nil {
return false
}
return true
}
func (set CharacterSet) Dscs() []byte {
dscsLen := 1
if set.dscsInter0 != nil {
if set.dscsInter1 == nil {
panic("Invalid DSCS intermediate 1!")
}
dscsLen = 3
}
dscs := make([]byte, dscsLen, dscsLen)
if dscsLen == 3 {
dscs[0] = *set.dscsInter0
dscs[1] = *set.dscsInter1
}
dscs[dscsLen-1] = set.dcscFinal
return dscs
}
func CharacterSetFromTable(t GraphicTable, id byte) CharacterSet {
set := CharacterSet{}
set.table = t
set.dcscFinal = id
set.lookup = lookupTable{}
for _, row := range set.table {
for _, graph := range row {
if graph == nil {
continue
}
set.lookup[*graph] = struct{}{}
}
}
return set
}
func CharacterSetFromArray(a [94]*rune) CharacterSet {
gto := CharacterSet{}
gto.lookup = lookupTable{}
var i int
for j, graph := range a {
i = j / 16
gto.table[i][j] = graph
if graph != nil {
gto.lookup[*graph] = struct{}{}
}
}
return gto
}
var (
mscASCIIGraphic = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C04R02)
mscSupplementalGraphic = CharacterSetFromTable(GraphicTable{
{N(nil), G('°'), G('À'), N(nil), G('à'), N(nil)},
{G('¡'), G('±'), G('Á'), G('Ñ'), G('á'), G('ñ')},
{G('¢'), G('²'), G('Â'), G('Ò'), G('â'), G('ò')},
{G('£'), G('³'), G('Ã'), G('Ó'), G('ã'), G('ó')},
{N(nil), N(nil), G('Ä'), G('Ô'), G('ä'), G('ô')},
{G('¥'), G('µ'), G('Å'), G('Õ'), G('å'), G('õ')},
{N(nil), G('¶'), G('Æ'), G('Ö'), G('æ'), G('ö')},
{G('§'), G('·'), G('Ç'), G('Œ'), G('ç'), G('œ')},
{G('¤'), N(nil), G('È'), G('Ø'), G('è'), G('ø')},
{G('©'), G('¹'), G('É'), G('Ù'), G('é'), G('ù')},
{G('ª'), G('º'), G('Ê'), G('Ú'), G('ê'), G('ú')},
{G('«'), G('»'), G('Ë'), G('Û'), G('ë'), G('û')},
{N(nil), G('¼'), G('Ì'), G('Ü'), G('ì'), G('ü')},
{N(nil), G('½'), G('Í'), G('Ÿ'), G('í'), G('ÿ')},
{N(nil), N(nil), G('Î'), N(nil), G('î'), N(nil)},
{N(nil), G('¿'), G('Ï'), G('ß'), G('ï'), N(nil)},
}, C03R12)
specialGraphics = CharacterSetFromTable(GraphicTable{
{N(nil), G('0'), G('@'), G('P'), G('♦'), G('⎻')},
{G('!'), G('1'), G('A'), G('Q'), G('█'), G('―')},
{G('"'), G('2'), G('B'), G('R'), G('␉'), G('⎼')},
{G('#'), G('3'), G('C'), G('S'), G('␌'), G('⎽')},
{G('$'), G('4'), G('D'), G('T'), G('␍'), G('├')},
{G('%'), G('5'), G('E'), G('U'), G('␊'), G('┤')},
{G('&'), G('6'), G('F'), G('V'), G('°'), G('┴')},
{G('\''), G('7'), G('G'), G('W'), G('±'), G('┬')},
{G('('), G('8'), G('H'), G('X'), G('␤'), G('│')},
{G(')'), G('9'), G('I'), G('Y'), G('␋'), G('≤')},
{G('*'), G(':'), G('J'), G('Z'), G('┘'), G('≥')},
{G('+'), G(';'), G('K'), G('['), G('┐'), G('π')},
{G(','), G('<'), G('L'), G('\\'), G('┌'), G('≠')},
{G('-'), G('='), G('M'), G(']'), G('└'), G('£')},
{G('.'), G('>'), G('N'), G('^'), G('┼'), G('·')},
{G('/'), G('?'), G('O'), G('\u2800'), G('⎺'), N(nil)},
}, C03R00)
// TODO: Correct to Match docs
nrcBritishBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C04R01)
// TODO: Correct to Match docs
nrcDutchBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C03R04)
// TODO: Correct to Match docs
nrcFinnishBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C04R03)
// TODO: Correct to Match docs
nrcFrenchBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C05R02)
// TODO: Correct to Match docs
nrcFrenchCanadianBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C05R01)
// TODO: Correct to Match docs
nrcGermanBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C04R11)
// TODO: Correct to Match docs
nrcItalianBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C05R09)
// TODO: Correct to Match docs
nrcNorwegianDanishBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C04R05)
// TODO: Correct to Match docs
nrcSpanishBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C05R10)
// TODO: Correct to Match docs
nrcSwedishBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C04R08)
// TODO: Correct to Match docs
nrcSwissBase = CharacterSetFromTable(GraphicTable{
{G(' '), G('0'), G('@'), G('P'), G('`'), G('p')},
{G('!'), G('1'), G('A'), G('Q'), G('a'), G('q')},
{G('"'), G('2'), G('B'), G('R'), G('b'), G('r')},
{G('#'), G('3'), G('C'), G('S'), G('c'), G('s')},
{G('$'), G('4'), G('D'), G('T'), G('d'), G('t')},
{G('%'), G('5'), G('E'), G('U'), G('e'), G('u')},
{G('&'), G('6'), G('F'), G('V'), G('f'), G('v')},
{G('\''), G('7'), G('G'), G('W'), G('g'), G('w')},
{G('('), G('8'), G('H'), G('X'), G('h'), G('x')},
{G(')'), G('9'), G('I'), G('Y'), G('i'), G('y')},
{G('*'), G(':'), G('J'), G('Z'), G('j'), G('z')},
{G('+'), G(';'), G('K'), G('['), G('k'), G('{')},
{G(','), G('<'), G('L'), G('\\'), G('l'), G('|')},
{G('-'), G('='), G('M'), G(']'), G('m'), G('}')},
{G('.'), G('>'), G('N'), G('^'), G('n'), G('~')},
{G('/'), G('?'), G('O'), G('_'), G('o'), G('\u007F')},
}, C03R13)
)
var graphicRepetoire = [15]*CharacterSet{
&mscASCIIGraphic,
&mscSupplementalGraphic,
&specialGraphics,
&nrcBritishBase,
&nrcDutchBase,
&nrcFinnishBase,
&nrcFrenchBase,
&nrcFrenchCanadianBase,
&nrcGermanBase,
&nrcItalianBase,
&nrcNorwegianDanishBase,
&nrcSpanishBase,
&nrcSwedishBase,
&nrcSwissBase,
nil,
}
var fontBuffer **CharacterSet = &graphicRepetoire[14]
var GraphicRepetoir = struct {
gr *[15]*CharacterSet
}{
gr: &graphicRepetoire,
}
func LoadDownLineCharacterSet(set *CharacterSet) error {
// TODO: Validate overlay (94 symbols max)
if set.decdld == nil {
return errors.New("CharacterSet has no DECDLD sequence.")
}
fmt.Print(set.decdld.String())
*fontBuffer = set
return nil
}
type graphicRegister struct {
dcs ControlSequencePrefix
set *CharacterSet
}
var graphicRegistry = [4]graphicRegister{
{dcs: DesignateCharSetR0CSP},
{dcs: DesignateCharSetR1CSP},
{dcs: DesignateCharSetR2CSP},
{dcs: DesignateCharSetR3CSP},
}
type GraphicRegister struct {
register *graphicRegister
}
func (r *GraphicRegister) Load(grIndex int) error {
if grIndex < 0 || grIndex > 14 {
return errors.New("Invalid Graphic Repetoire Index")
}
// Invoke designation control sequence.
fmt.Print(r.register.dcs.With(graphicRepetoire[grIndex].Dscs()...).String())
r.register.set = graphicRepetoire[grIndex]
return nil
}
var (
G0 = GraphicRegister{
register: &graphicRegistry[0],
}
G1 = GraphicRegister{
register: &graphicRegistry[1],
}
G2 = GraphicRegister{
register: &graphicRegistry[2],
}
G3 = GraphicRegister{
register: &graphicRegistry[3],
}
)
type MSC struct {
ASCIIGraphic *CharacterSet
SupplementalGraphic *CharacterSet
}
type NRC struct {
British *CharacterSet
Dutch *CharacterSet
Finnish *CharacterSet
French *CharacterSet
FrenchCanadian *CharacterSet
German *CharacterSet
Italian *CharacterSet
NorwegianDanish *CharacterSet
Spanish *CharacterSet
Swedish *CharacterSet
Swiss *CharacterSet
}
var DEC = struct {
MSC MSC
SpecialGraphics *CharacterSet
NRC NRC
}{
MSC: MSC{
ASCIIGraphic: &mscASCIIGraphic,
SupplementalGraphic: &mscSupplementalGraphic,
},
SpecialGraphics: &specialGraphics,
NRC: NRC{
British: &nrcBritishBase,
Dutch: &nrcDutchBase,
Finnish: &nrcFinnishBase,
French: &nrcFrenchBase,
FrenchCanadian: &nrcFrenchCanadianBase,
German: &nrcGermanBase,
Italian: &nrcItalianBase,
NorwegianDanish: &nrcNorwegianDanishBase,
Spanish: &nrcSpanishBase,
Swedish: &nrcSwedishBase,
Swiss: &nrcSwissBase,
},
}

94
main.go Normal file
View File

@ -0,0 +1,94 @@
package main
import (
"fmt"
"time"
)
var testMSCASCIIGraphic = [16][6]rune{
{' ', '0', '@', 'P', '`', 'p'},
{'!', '1', 'A', 'Q', 'a', 'q'},
{'"', '2', 'B', 'R', 'b', 'r'},
{'#', '3', 'C', 'S', 'c', 's'},
{'$', '4', 'D', 'T', 'd', 't'},
{'%', '5', 'E', 'U', 'e', 'u'},
{'&', '6', 'F', 'V', 'f', 'v'},
{'\'', '7', 'G', 'W', 'g', 'w'},
{'(', '8', 'H', 'X', 'h', 'x'},
{')', '9', 'I', 'Y', 'i', 'y'},
{'*', ':', 'J', 'Z', 'j', 'z'},
{'+', ';', 'K', '[', 'k', '{'},
{',', '<', 'L', '\\', 'l', '|'},
{'-', '=', 'M', ']', 'm', '}'},
{'.', '>', 'N', '^', 'n', '~'},
{'/', '?', 'O', '_', 'o', '\u007F'},
}
var testMSCSupplementalGraphic = [16][6]rune{
{0, '°', 'À', 0, 'à', 0},
{'¡', '±', 'Á', 'Ñ', 'á', 'ñ'},
{'¢', '²', 'Â', 'Ò', 'â', 'ò'},
{'£', '³', 'Ã', 'Ó', 'ã', 'ó'},
{0, 0, 'Ä', 'Ô', 'ä', 'ô'},
{'¥', 'µ', 'Å', 'Õ', 'å', 'õ'},
{0, '¶', 'Æ', 'Ö', 'æ', 'ö'},
{'§', '·', 'Ç', 'Œ', 'ç', 'œ'},
{'¤', 0, 'È', 'Ø', 'è', 'ø'},
{'©', '¹', 'É', 'Ù', 'é', 'ù'},
{'ª', 'º', 'Ê', 'Ú', 'ê', 'ú'},
{'«', '»', 'Ë', 'Û', 'ë', 'û'},
{0, '¼', 'Ì', 'Ü', 'ì', 'ü'},
{0, '½', 'Í', 'Ÿ', 'í', 'ÿ'},
{0, 0, 'Î', 0, 'î', 0},
{0, '¿', 'Ï', 'ß', 'ï', 0},
}
var testSpecialGraphics = [16][6]rune{
{0, '0', '@', 'P', '♦', '⎻'},
{'!', '1', 'A', 'Q', '█', '―'},
{'"', '2', 'B', 'R', '␉', '⎼'},
{'#', '3', 'C', 'S', '␌', '⎽'},
{'$', '4', 'D', 'T', '␍', '├'},
{'%', '5', 'E', 'U', '␊', '┤'},
{'&', '6', 'F', 'V', '°', '┴'},
{'\'', '7', 'G', 'W', '±', '┬'},
{'(', '8', 'H', 'X', '␤', '│'},
{')', '9', 'I', 'Y', '␋', '≤'},
{'*', ':', 'J', 'Z', '┘', '≥'},
{'+', ';', 'K', '[', '┐', 'π'},
{',', '<', 'L', '\\', '┌', '≠'},
{'-', '=', 'M', ']', '└', '£'},
{'.', '>', 'N', '^', '┼', '·'},
{'/', '?', 'O', '\u2800', '⎺', 0},
}
func printTest(sl, sr [16][6]rune) {
for i := 0; i < 16; i++ {
for j := 0; j < 12; j++ {
fmt.Print(" ")
if j == 6 {
fmt.Print(" ")
}
var r rune
if j < 6 {
r = sl[i][j]
} else {
r = sr[i][j-6]
}
if r == 0 || r == '\u007F' {
fmt.Print(" ")
continue
}
fmt.Print(MustTrans(r))
}
fmt.Print("\n")
time.Sleep(time.Millisecond * 250)
}
fmt.Print("\n")
}
func main() {
fmt.Print(CS.LockShiftG2Right.String())
printTest(testMSCASCIIGraphic, testMSCSupplementalGraphic)
fmt.Print(CS.LockShiftG1Right.String())
}