implement io.Writer

This commit is contained in:
Diego Fernando Carrión 2024-08-11 17:58:11 +02:00
parent 1d97a34694
commit aa5bfce2cb
Signed by: CRThaze
GPG Key ID: 8279B79A1A7F8194
7 changed files with 810 additions and 455 deletions

View File

@ -2,14 +2,17 @@ package main
import (
"errors"
"fmt"
"io"
)
type controlRow [2]byte
type controlTable [16]controlRow
type rangeLookup map[rune]*byte
type ControlRange struct {
table controlTable
set rangeLookup
colOffset uint8
}
@ -20,15 +23,22 @@ func (r *ControlRange) Get(col, row int) (byte, error) {
return glTable[row][col-int(r.colOffset)], nil
}
func (r *ControlRange) Lookup(ru rune) *byte {
if point, ok := r.set[ru]; ok {
return point
}
return nil
}
type graphicRow [6]byte
type graphicTable [16]graphicRow
type rangeLookup map[rune]*byte
type GraphicRange struct {
table graphicTable
set rangeLookup
colOffset uint8
table graphicTable
set rangeLookup
colOffset uint8
lockShifts map[GraphicRegister]ControlSequence
singleShifts map[GraphicRegister]ControlSequence
}
func (r *GraphicRange) Get(col, row int) (byte, error) {
@ -59,9 +69,42 @@ func (r *GraphicRange) load(gOverlay *CharacterSet) {
}
}
func (rg *GraphicRange) LockShift(register GraphicRegister, w io.Writer) error {
if rg.lockShifts == nil {
return errors.New("Register does not have defined Lock Shifts")
}
if _, ok := rg.lockShifts[register]; !ok {
return errors.New("This register cannot be Lock Shifted into this Range.")
}
rg.lockShifts[register].Invoke(w)
rg.load(register.register.set)
return nil
}
// func (rg *GraphicRange) SingleShift(register GraphicRegister, r rune) ([]byte, error) {
// if rg.singleShifts == nil {
// return nil, errors.New("Register does not have defined Single Shifts")
// }
// if _, ok := rg.singleShifts[register]; !ok {
// return nil, errors.New("This register cannot be Single Shifted into this Range.")
// }
// coords := register.register.set.lookup.Get(r)
// if coords == nil {
// return nil, errors.New("The character set in this Register does not contain the given rune.")
// }
// ba := make([]byte, 0, 3)
// ba = append(ba, rg.singleShifts[register].Bytes()...)
// ba = append(ba, rg.table[coords[0]][coords[1]])
// return ba, nil
// }
func (rg *GraphicRange) Load(register GraphicRegister) error {
return rg.Load(register)
}
const (
// Column 0
C00R00 = 0b0000_0000 + iota
C00R00 byte = 0b0000_0000 + iota
C00R01
C00R02
C00R03
@ -334,7 +377,9 @@ const (
C15R15
)
const UNKNOWN = C03R15 // 0b0011_1111
// Negative Question Mark.
// var UNKNOWN = NewControlSequence(CSI, C03R07, C06R13, C03R15, CSI, C03R00, C06R13).Bytes()
var UNKNOWN = append(append(SGR(SGRPs.Negative).Bytes(), C03R15), SGR(SGRPs.Positive).Bytes()...)
const (
NUL = C00R00
@ -390,10 +435,19 @@ var c0Table controlTable = controlTable{
controlRow{SI, US},
}
var C0 ControlRange = ControlRange{
table: c0Table,
colOffset: 0,
}
// var C0 ControlRange = ControlRange{
// table: c0Table,
// colOffset: 0,
// set: rangeLookup{
// '\a': &c0Table[7][0],
// '\b': &c0Table[8][0],
// '\t': &c0Table[9][0],
// '\n': &c0Table[10][0],
// '\v': &c0Table[11][0],
// '\f': &c0Table[12][0],
// '\r': &c0Table[13][0],
// },
// }
var glTable graphicTable = graphicTable{
graphicRow{C02R00, C03R00, C04R00, C05R00, C06R00, C07R00},
@ -414,10 +468,20 @@ var glTable graphicTable = graphicTable{
graphicRow{C02R15, C03R15, C04R15, C05R15, C06R15, C07R15},
}
var GL GraphicRange = GraphicRange{
table: glTable,
colOffset: 2,
}
// var GL GraphicRange = GraphicRange{
// table: glTable,
// colOffset: 2,
// lockShifts: map[GraphicRegister]ControlSequence{
// G0: ShiftCtrl.LockShiftG0,
// G1: ShiftCtrl.LockShiftG1,
// G2: ShiftCtrl.LockShiftG2,
// G3: ShiftCtrl.LockShiftG3,
// },
// singleShifts: map[GraphicRegister]ControlSequence{
// G2: ShiftCtrl.SingleShiftG2,
// G3: ShiftCtrl.SingleShiftG3,
// },
// }
const (
IND = C08R04
@ -466,10 +530,10 @@ var c1Table controlTable = controlTable{
controlRow{SS3, APC},
}
var C1 ControlRange = ControlRange{
table: c1Table,
colOffset: 8,
}
// var C1 ControlRange = ControlRange{
// table: c1Table,
// colOffset: 8,
// }
var grTable graphicTable = graphicTable{
graphicRow{C10R00, C11R00, C12R00, C13R00, C14R00, C15R00},
@ -490,75 +554,20 @@ var grTable graphicTable = graphicTable{
graphicRow{C10R15, C11R15, C12R15, C13R15, C14R15, C15R15},
}
var GR GraphicRange = GraphicRange{
table: grTable,
colOffset: 10,
}
// var GR GraphicRange = GraphicRange{
// table: grTable,
// colOffset: 10,
// lockShifts: map[GraphicRegister]ControlSequence{
// G1: ShiftCtrl.LockShiftG1Right,
// G2: ShiftCtrl.LockShiftG2Right,
// G3: ShiftCtrl.LockShiftG3Right,
// },
// }
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 ""
}
// func init() {
// GL.load(DEC.MSC.ASCIIGraphic)
// GR.load(DEC.MSC.SupplementalGraphic)
// G0.Load(0)
// G1.Load(1)
// G2.Load(2)
// }

View File

@ -1,5 +1,9 @@
package main
import (
"io"
)
// type sequence uint64
// type ControlSequence struct {
// seq sequence
@ -60,8 +64,12 @@ func (seq ControlSequence) Bytes() []byte {
return seq.seq
}
func (seq ControlSequence) String() string {
return string(seq.Bytes()[:])
// func (seq ControlSequence) String() string {
// return string(seq.Bytes()[:])
// }
func (seq ControlSequence) Invoke(w io.Writer) {
w.Write(seq.Bytes())
}
type ControlSequencePrefix struct {
@ -90,16 +98,47 @@ func (pfx ControlSequencePrefix) With(bs ...byte) ControlSequence {
return ControlSequence{seq: ba}
}
type SGRAttr struct {
ps byte
not bool
}
func SGR(attrs ...SGRAttr) ControlSequence {
// https://web.archive.org/web/20230928233241/https://vt100.net/docs/vt220-rm/chapter4.html#S4.9
//
// Set the capacity to 2 (initialization + termination) + 3 * total attrs.
// Attr Ps can be up to two bytes (if negated) and when multiple are present they need one
// extra byte for delimitation.
ba := make([]byte, 0, (2 + (len(attrs) * 3)))
// Append SGR sequence initialization control character.
ba = append(ba, CSI)
for i, attr := range attrs {
if i > 0 {
// Append Ps delimiter.
ba = append(ba, C03R11)
}
if attr.not {
// Append negation byte.
ba = append(ba, C03R02)
}
// Append attr ID byte.
ba = append(ba, attr.ps)
}
// Append SGR terminator.
ba = append(ba, C06R13)
return NewControlSequence(ba...)
}
var (
// Prefixes
EscapeCSP = NewControlSequencePrefix(ESC)
DesignateCharSetR0CSP = EscapeCSP.Append(C02R08)
DesignateCharSetR1CSP = EscapeCSP.Append(C02R09)
DesignateCharSetR2CSP = EscapeCSP.Append(C02R10)
DesignateCharSetR3CSP = EscapeCSP.Append(C02R11)
// Complete Sequences
EscapeCtrlPfx = NewControlSequencePrefix(ESC)
DesignateCharSetR0CtrlPfx = EscapeCtrlPfx.Append(C02R08)
DesignateCharSetR1CtrlPfx = EscapeCtrlPfx.Append(C02R09)
DesignateCharSetR2CtrlPfx = EscapeCtrlPfx.Append(C02R10)
DesignateCharSetR3CtrlPfx = EscapeCtrlPfx.Append(C02R11)
CS = struct {
// Complete Sequences
ShiftCtrl = struct {
LockShiftG0,
LockShiftG1,
LockShiftG1Right,
@ -109,22 +148,6 @@ var (
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,
@ -135,14 +158,73 @@ var (
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,
// Lock Shifts
LockShiftG0: NewControlSequence(SI),
LockShiftG1: NewControlSequence(SO),
LockShiftG1Right: EscapeCtrlPfx.With(C07R14),
LockShiftG2: EscapeCtrlPfx.With(C06R14),
LockShiftG2Right: EscapeCtrlPfx.With(C07R13),
LockShiftG3: EscapeCtrlPfx.With(C06R15),
LockShiftG3Right: EscapeCtrlPfx.With(C07R12),
// Single Shifts
SingleShiftG2: NewControlSequence(SS2),
SingleShiftG3: NewControlSequence(SS3),
}
SGRPs = struct {
AllAttrsOff,
Bold,
Underline,
Blink,
Negative,
NoBold,
NoUnderline,
NoBlink,
Positive SGRAttr
}{
AllAttrsOff: SGRAttr{
ps: C03R00,
},
Bold: SGRAttr{
ps: C03R01,
},
Underline: SGRAttr{
ps: C03R04,
},
Blink: SGRAttr{
ps: C03R07,
},
Negative: SGRAttr{
ps: C03R07,
},
NoBold: SGRAttr{
ps: C03R01,
not: true,
},
NoUnderline: SGRAttr{
ps: C03R04,
not: true,
},
NoBlink: SGRAttr{
ps: C03R07,
not: true,
},
Positive: SGRAttr{
ps: C03R07,
not: true,
},
}
)
func init() {
ShiftCtrl.LS0 = ShiftCtrl.LockShiftG0
ShiftCtrl.LS1 = ShiftCtrl.LockShiftG1
ShiftCtrl.LS1R = ShiftCtrl.LockShiftG1Right
ShiftCtrl.LS2 = ShiftCtrl.LockShiftG2
ShiftCtrl.LS2R = ShiftCtrl.LockShiftG2Right
ShiftCtrl.LS3 = ShiftCtrl.LockShiftG3
ShiftCtrl.LS3R = ShiftCtrl.LockShiftG3Right
ShiftCtrl.SS2 = ShiftCtrl.SingleShiftG2
ShiftCtrl.SS3 = ShiftCtrl.SingleShiftG3
}

20
equivalence.go Normal file
View File

@ -0,0 +1,20 @@
package main
type equivalenceTable map[rune]rune
type EquivalenceTable struct {
et equivalenceTable
}
func (table EquivalenceTable) Normalize(r rune) rune {
if normal, ok := table.et[r]; ok {
return normal
}
return r
}
var Equivalence = EquivalenceTable{
et: equivalenceTable{
'a': 'a',
},
}

View File

@ -1,10 +1,5 @@
package main
import (
"errors"
"fmt"
)
type Grapheme *rune
func G(r rune) Grapheme {
@ -15,9 +10,9 @@ func N(r *rune) Grapheme {
return r
}
type GraphicRow [6]Grapheme
type GraphicTable [16]GraphicRow
type lookupTable map[rune]struct{}
type GraphemeTableRow [6]Grapheme
type GraphemeTable [16]GraphemeTableRow
type lookupTable map[rune][2]int
func (t lookupTable) Has(r rune) bool {
if _, ok := t[r]; ok {
@ -26,15 +21,15 @@ func (t lookupTable) Has(r rune) bool {
return false
}
func (t lookupTable) Get(r rune) *rune {
if !t.Has(r) {
return nil
func (t lookupTable) Get(r rune) *[2]int {
if coords, ok := t[r]; ok {
return &coords
}
return &r
return nil
}
type CharacterSet struct {
table GraphicTable
table GraphemeTable
lookup lookupTable
dscsInter0 *byte
dscsInter1 *byte
@ -49,6 +44,7 @@ func (set CharacterSet) IsDownLineLoadable() bool {
return true
}
// Dscs returns the DEC-Select-Character-Set byte sequence for this CharacterSet.
func (set CharacterSet) Dscs() []byte {
dscsLen := 1
if set.dscsInter0 != nil {
@ -66,23 +62,23 @@ func (set CharacterSet) Dscs() []byte {
return dscs
}
func CharacterSetFromTable(t GraphicTable, id byte) CharacterSet {
func CharacterSetFromTable(t GraphemeTable, id byte) *CharacterSet {
set := CharacterSet{}
set.table = t
set.dcscFinal = id
set.lookup = lookupTable{}
for _, row := range set.table {
for _, graph := range row {
for i, row := range set.table {
for j, graph := range row {
if graph == nil {
continue
}
set.lookup[*graph] = struct{}{}
set.lookup[*graph] = [2]int{i, j}
}
}
return set
return &set
}
func CharacterSetFromArray(a [94]*rune) CharacterSet {
func CharacterSetFromArray(a [94]*rune) *CharacterSet {
gto := CharacterSet{}
gto.lookup = lookupTable{}
var i int
@ -90,14 +86,14 @@ func CharacterSetFromArray(a [94]*rune) CharacterSet {
i = j / 16
gto.table[i][j] = graph
if graph != nil {
gto.lookup[*graph] = struct{}{}
gto.lookup[*graph] = [2]int{i, j}
}
}
return gto
return &gto
}
var (
mscASCIIGraphic = CharacterSetFromTable(GraphicTable{
mscASCIIGraphic = GraphemeTable{
{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')},
@ -114,8 +110,8 @@ var (
{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{
}
mscSupplementalGraphic = GraphemeTable{
{N(nil), G('°'), G('À'), N(nil), G('à'), N(nil)},
{G('¡'), G('±'), G('Á'), G('Ñ'), G('á'), G('ñ')},
{G('¢'), G('²'), G('Â'), G('Ò'), G('â'), G('ò')},
@ -132,8 +128,8 @@ var (
{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{
}
specialGraphics = GraphemeTable{
{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('⎼')},
@ -150,317 +146,272 @@ var (
{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")
// TODO: Correct to Match docs
nrcBritishBase = GraphemeTable{
{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')},
}
// 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],
// TODO: Correct to Match docs
nrcDutchBase = GraphemeTable{
{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')},
}
G1 = GraphicRegister{
register: &graphicRegistry[1],
// TODO: Correct to Match docs
nrcFinnishBase = GraphemeTable{
{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')},
}
G2 = GraphicRegister{
register: &graphicRegistry[2],
// TODO: Correct to Match docs
nrcFrenchBase = GraphemeTable{
{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')},
}
G3 = GraphicRegister{
register: &graphicRegistry[3],
// TODO: Correct to Match docs
nrcFrenchCanadianBase = GraphemeTable{
{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')},
}
// TODO: Correct to Match docs
nrcGermanBase = GraphemeTable{
{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')},
}
// TODO: Correct to Match docs
nrcItalianBase = GraphemeTable{
{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')},
}
// TODO: Correct to Match docs
nrcNorwegianDanishBase = GraphemeTable{
{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')},
}
// TODO: Correct to Match docs
nrcSpanishBase = GraphemeTable{
{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')},
}
// TODO: Correct to Match docs
nrcSwedishBase = GraphemeTable{
{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')},
}
// TODO: Correct to Match docs
nrcSwissBase = GraphemeTable{
{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')},
}
)
// var graphicRegistry = [4]graphicRegister{
// {dcs: DesignateCharSetR0CtrlPfx},
// {dcs: DesignateCharSetR1CtrlPfx},
// {dcs: DesignateCharSetR2CtrlPfx},
// {dcs: DesignateCharSetR3CtrlPfx},
// }
// func (r *GraphicRegister) Load(grIndex int, w io.Writer) error {
// if grIndex < 0 || grIndex > 14 {
// return errors.New("Invalid Graphic Repetoire Index")
// }
// // Invoke designation control sequence.
// w.Write(r.register.dcs.With(graphicRepetoire[grIndex].Dscs()...).Bytes())
// 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
ASCIIGraphic *GraphemeTable
SupplementalGraphic *GraphemeTable
}
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
British *GraphemeTable
Dutch *GraphemeTable
Finnish *GraphemeTable
French *GraphemeTable
FrenchCanadian *GraphemeTable
German *GraphemeTable
Italian *GraphemeTable
NorwegianDanish *GraphemeTable
Spanish *GraphemeTable
Swedish *GraphemeTable
Swiss *GraphemeTable
}
var DEC = struct {
MSC MSC
SpecialGraphics *CharacterSet
SpecialGraphics *GraphemeTable
NRC NRC
}{
MSC: MSC{

23
main.go
View File

@ -1,10 +1,12 @@
package main
import (
"fmt"
"os"
"time"
)
var term = NewVTTerm(VT220Type, os.Stdout)
var testMSCASCIIGraphic = [16][6]rune{
{' ', '0', '@', 'P', '`', 'p'},
{'!', '1', 'A', 'Q', 'a', 'q'},
@ -65,9 +67,9 @@ var testSpecialGraphics = [16][6]rune{
func printTest(sl, sr [16][6]rune) {
for i := 0; i < 16; i++ {
for j := 0; j < 12; j++ {
fmt.Print(" ")
term.Print(" ")
if j == 6 {
fmt.Print(" ")
term.Print(" ")
}
var r rune
if j < 6 {
@ -76,19 +78,22 @@ func printTest(sl, sr [16][6]rune) {
r = sr[i][j-6]
}
if r == 0 || r == '\u007F' {
fmt.Print(" ")
term.Print(" ")
continue
}
fmt.Print(MustTrans(r))
// fmt.Print(string(MustTransRune(r)[:]))
term.Print(string(r))
}
fmt.Print("\n")
term.Print("\n")
time.Sleep(time.Millisecond * 250)
}
fmt.Print("\n")
term.Print("\n")
}
func main() {
fmt.Print(CS.LockShiftG2Right.String())
term.Init()
printTest(testMSCASCIIGraphic, testMSCSupplementalGraphic)
fmt.Print(CS.LockShiftG1Right.String())
// GR.Load(G2)
printTest(testMSCASCIIGraphic, testSpecialGraphics)
// GR.Load(G1)
}

35
term.go Normal file
View File

@ -0,0 +1,35 @@
package main
import (
"io"
)
type TermType struct {
id string
}
func (id TermType) ID() string {
return id.id
}
func (id TermType) String() string {
return id.ID()
}
type VTTerm interface {
io.Writer
Init()
TermID() string
Print(a ...any) (n int, err error)
Printf(format string, a ...any) (n int, err error)
Println(a ...any) (n int, err error)
}
func NewVTTerm(ttype TermType, w io.Writer) VTTerm {
var term VTTerm
switch ttype {
case VT220Type:
term = newVT220(w)
}
return term
}

253
vt220.go Normal file
View File

@ -0,0 +1,253 @@
package main
import (
"bytes"
"errors"
"fmt"
"io"
)
var (
VT220Type = TermType{"vt220"}
)
type graphicRegister struct {
dcs ControlSequencePrefix
set *CharacterSet
}
type GraphicRegister struct {
register *graphicRegister
}
type VT220 struct {
writer io.Writer
C0 ControlRange
GL GraphicRange
C1 ControlRange
GR GraphicRange
G0 GraphicRegister
G1 GraphicRegister
G2 GraphicRegister
G3 GraphicRegister
graphicRegistry [4]graphicRegister
graphicRepetoire [15]*CharacterSet
fontBuffer **CharacterSet
}
func newVT220(w io.Writer) *VT220 {
return &VT220{
writer: w,
C0: ControlRange{
table: c0Table,
colOffset: 0,
set: rangeLookup{
'\a': &c0Table[7][0],
'\b': &c0Table[8][0],
'\t': &c0Table[9][0],
'\n': &c0Table[10][0],
'\v': &c0Table[11][0],
'\f': &c0Table[12][0],
'\r': &c0Table[13][0],
},
},
GL: GraphicRange{
table: glTable,
colOffset: 2,
},
C1: ControlRange{
table: c1Table,
colOffset: 8,
},
GR: GraphicRange{
table: grTable,
colOffset: 10,
},
}
}
func (vt *VT220) Init() {
vt.GL.lockShifts = map[GraphicRegister]ControlSequence{
vt.G0: ShiftCtrl.LockShiftG0,
vt.G1: ShiftCtrl.LockShiftG1,
vt.G2: ShiftCtrl.LockShiftG2,
vt.G3: ShiftCtrl.LockShiftG3,
}
vt.GL.singleShifts = map[GraphicRegister]ControlSequence{
vt.G2: ShiftCtrl.SingleShiftG2,
vt.G3: ShiftCtrl.SingleShiftG3,
}
vt.GR.lockShifts = map[GraphicRegister]ControlSequence{
vt.G1: ShiftCtrl.LockShiftG1Right,
vt.G2: ShiftCtrl.LockShiftG2Right,
vt.G3: ShiftCtrl.LockShiftG3Right,
}
vt.graphicRepetoire = [15]*CharacterSet{
CharacterSetFromTable(mscASCIIGraphic, C04R02),
CharacterSetFromTable(mscSupplementalGraphic, C03R12),
CharacterSetFromTable(specialGraphics, C03R00),
CharacterSetFromTable(nrcBritishBase, C04R01),
CharacterSetFromTable(nrcDutchBase, C03R04),
CharacterSetFromTable(nrcFinnishBase, C04R03),
CharacterSetFromTable(nrcFrenchBase, C05R02),
CharacterSetFromTable(nrcFrenchCanadianBase, C05R01),
CharacterSetFromTable(nrcGermanBase, C04R11),
CharacterSetFromTable(nrcItalianBase, C05R09),
CharacterSetFromTable(nrcNorwegianDanishBase, C04R05),
CharacterSetFromTable(nrcSpanishBase, C05R10),
CharacterSetFromTable(nrcSwedishBase, C04R08),
CharacterSetFromTable(nrcSwissBase, C03R13),
nil,
}
vt.fontBuffer = &vt.graphicRepetoire[14]
vt.graphicRegistry = [4]graphicRegister{
{dcs: DesignateCharSetR0CtrlPfx},
{dcs: DesignateCharSetR1CtrlPfx},
{dcs: DesignateCharSetR2CtrlPfx},
{dcs: DesignateCharSetR3CtrlPfx},
}
vt.GL.load(vt.graphicRepetoire[0])
vt.GR.load(vt.graphicRepetoire[1])
vt.DesignateCharSet(0, 0)
vt.DesignateCharSet(1, 1)
vt.DesignateCharSet(2, 2)
}
func (vt *VT220) DesignateCharSet(grIndex, register int) error {
if grIndex < 0 || grIndex > 14 {
return errors.New("Invalid Graphic Repetoire Index")
}
if register < 0 || register > 3 {
return errors.New("Invalid Graphic Register")
}
// Invoke designation control sequence.
vt.graphicRegistry[register].dcs.With(vt.graphicRepetoire[grIndex].Dscs()...).Invoke(vt.writer)
vt.graphicRegistry[register].set = vt.graphicRepetoire[grIndex]
return nil
}
func (vt *VT220) LoadDownLineCharacterSet(set *CharacterSet, w io.Writer) error {
// TODO: Validate overlay (94 symbols max)
if set.decdld == nil {
return errors.New("CharacterSet has no DECDLD sequence.")
}
w.Write(set.decdld.Bytes())
*vt.fontBuffer = set
return nil
}
func (t VT220) TermID() string {
return "vt220"
}
// 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 (vt *VT220) Trans(r rune) ([]byte, error) {
ba := [1]byte{}
if b := vt.C0.Lookup(r); b != nil {
ba[0] = *b
} else if b := vt.GL.Lookup(r); b != nil {
ba[0] = *b
} else if b := vt.GR.Lookup(r); b != nil {
ba[0] = *b
} else {
return nil, errors.New("No translation for rune.")
}
return 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 (vt *VT220) MustTrans(r rune) []byte {
if bs, err := vt.Trans(r); err == nil {
return bs
}
bs := UNKNOWN
return bs[:]
}
// SafeTrans uses an equivalency table to normalize the given rune if it is visually similar
// enough to a unicode character mapped in the Graphic Repetoire.
// It then calls MustTrans with the normalized rune.
func (vt *VT220) SafeTrans(r rune) []byte {
return vt.MustTrans(Equivalence.Normalize(r))
}
// 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 (vt *VT220) TransDynamic(r rune) []byte {
// if s, err := TransRune(r); err == nil {
// return s
// }
// if G2.register.set.lookup.Has(r) {
// if ba, err := GL.SingleShift(G2, r); err == nil {
// return string(ba[:])
// } else {
// panic(err)
// }
// }
// if G3.register.set.lookup.Has(r) {
// if ba, err := GL.SingleShift(G3, r); err == nil {
// return string(ba[:])
// } else {
// panic(err)
// }
// }
// if G1.register.set.lookup.Has(r) {
// // prevG2set := G2.register.set
// // G2.Load()
// }
// for _, set := range GraphicRepetoir.gr {
// if _, ok := set.lookup[r]; !ok {
// continue
// }
// if *set.table[0][0] == r {
// // TODO: load
// }
// }
// // TODO: return UNKNOWN
// // return string(ba[:])
return vt.MustTrans(r)
}
// 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 (vt *VT220) SafeTransDynamic(r rune) []byte {
return vt.TransDynamic(Equivalence.Normalize(r))
}
func (vt VT220) write(buf *bytes.Buffer) (n int, err error) {
for r, _, e := buf.ReadRune(); e != io.EOF; r, _, e = buf.ReadRune() {
if e != nil {
err = e
return
}
var bn int
bn, err = vt.writer.Write(vt.SafeTransDynamic(r))
n += bn
if err != nil {
return
}
}
return
}
func (t VT220) Write(p []byte) (n int, err error) {
return t.write(bytes.NewBuffer(p))
}
func (t VT220) Print(a ...any) (n int, err error) {
return t.write(bytes.NewBufferString(fmt.Sprint(a...)))
}
func (t VT220) Printf(format string, a ...any) (n int, err error) {
return t.Print(fmt.Sprintf(format, a...))
}
func (t VT220) Println(a ...any) (n int, err error) {
return t.Print(fmt.Sprintln(a...))
}