summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/xo/terminfo/util.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/xo/terminfo/util.go')
-rw-r--r--vendor/github.com/xo/terminfo/util.go266
1 files changed, 266 insertions, 0 deletions
diff --git a/vendor/github.com/xo/terminfo/util.go b/vendor/github.com/xo/terminfo/util.go
new file mode 100644
index 000000000..56f47e811
--- /dev/null
+++ b/vendor/github.com/xo/terminfo/util.go
@@ -0,0 +1,266 @@
+package terminfo
+
+import (
+ "sort"
+)
+
+const (
+ // maxFileLength is the max file length.
+ maxFileLength = 4096
+
+ // magic is the file magic for terminfo files.
+ magic = 0432
+
+ // magicExtended is the file magic for terminfo files with the extended number format.
+ magicExtended = 01036
+)
+
+// header fields.
+const (
+ fieldMagic = iota
+ fieldNameSize
+ fieldBoolCount
+ fieldNumCount
+ fieldStringCount
+ fieldTableSize
+)
+
+// header extended fields.
+const (
+ fieldExtBoolCount = iota
+ fieldExtNumCount
+ fieldExtStringCount
+ fieldExtOffsetCount
+ fieldExtTableSize
+)
+
+// hasInvalidCaps determines if the capabilities in h are invalid.
+func hasInvalidCaps(h []int) bool {
+ return h[fieldBoolCount] > CapCountBool ||
+ h[fieldNumCount] > CapCountNum ||
+ h[fieldStringCount] > CapCountString
+}
+
+// capLength returns the total length of the capabilities in bytes.
+func capLength(h []int) int {
+ return h[fieldNameSize] +
+ h[fieldBoolCount] +
+ (h[fieldNameSize]+h[fieldBoolCount])%2 + // account for word align
+ h[fieldNumCount]*2 +
+ h[fieldStringCount]*2 +
+ h[fieldTableSize]
+}
+
+// hasInvalidExtOffset determines if the extended offset field is valid.
+func hasInvalidExtOffset(h []int) bool {
+ return h[fieldExtBoolCount]+
+ h[fieldExtNumCount]+
+ h[fieldExtStringCount]*2 != h[fieldExtOffsetCount]
+}
+
+// extCapLength returns the total length of extended capabilities in bytes.
+func extCapLength(h []int, numWidth int) int {
+ return h[fieldExtBoolCount] +
+ h[fieldExtBoolCount]%2 + // account for word align
+ h[fieldExtNumCount]*(numWidth/8) +
+ h[fieldExtOffsetCount]*2 +
+ h[fieldExtTableSize]
+}
+
+// findNull finds the position of null in buf.
+func findNull(buf []byte, i int) int {
+ for ; i < len(buf); i++ {
+ if buf[i] == 0 {
+ return i
+ }
+ }
+ return -1
+}
+
+// readStrings decodes n strings from string data table buf using the indexes in idx.
+func readStrings(idx []int, buf []byte, n int) (map[int][]byte, int, error) {
+ var last int
+ m := make(map[int][]byte)
+ for i := 0; i < n; i++ {
+ start := idx[i]
+ if start < 0 {
+ continue
+ }
+ if end := findNull(buf, start); end != -1 {
+ m[i], last = buf[start:end], end+1
+ } else {
+ return nil, 0, ErrInvalidStringTable
+ }
+ }
+ return m, last, nil
+}
+
+// decoder holds state info while decoding a terminfo file.
+type decoder struct {
+ buf []byte
+ pos int
+ len int
+}
+
+// readBytes reads the next n bytes of buf, incrementing pos by n.
+func (d *decoder) readBytes(n int) ([]byte, error) {
+ if d.len < d.pos+n {
+ return nil, ErrUnexpectedFileEnd
+ }
+ n, d.pos = d.pos, d.pos+n
+ return d.buf[n:d.pos], nil
+}
+
+// readInts reads n number of ints with width w.
+func (d *decoder) readInts(n, w int) ([]int, error) {
+ w /= 8
+ l := n * w
+
+ buf, err := d.readBytes(l)
+ if err != nil {
+ return nil, err
+ }
+
+ // align
+ d.pos += d.pos % 2
+
+ z := make([]int, n)
+ for i, j := 0, 0; i < l; i, j = i+w, j+1 {
+ switch w {
+ case 1:
+ z[i] = int(buf[i])
+ case 2:
+ z[j] = int(int16(buf[i+1])<<8 | int16(buf[i]))
+ case 4:
+ z[j] = int(buf[i+3])<<24 | int(buf[i+2])<<16 | int(buf[i+1])<<8 | int(buf[i])
+ }
+ }
+
+ return z, nil
+}
+
+// readBools reads the next n bools.
+func (d *decoder) readBools(n int) (map[int]bool, map[int]bool, error) {
+ buf, err := d.readInts(n, 8)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // process
+ bools, boolsM := make(map[int]bool), make(map[int]bool)
+ for i, b := range buf {
+ bools[i] = b == 1
+ if int8(b) == -2 {
+ boolsM[i] = true
+ }
+ }
+
+ return bools, boolsM, nil
+}
+
+// readNums reads the next n nums.
+func (d *decoder) readNums(n, w int) (map[int]int, map[int]bool, error) {
+ buf, err := d.readInts(n, w)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // process
+ nums, numsM := make(map[int]int), make(map[int]bool)
+ for i := 0; i < n; i++ {
+ nums[i] = buf[i]
+ if buf[i] == -2 {
+ numsM[i] = true
+ }
+ }
+
+ return nums, numsM, nil
+}
+
+// readStringTable reads the string data for n strings and the accompanying data
+// table of length sz.
+func (d *decoder) readStringTable(n, sz int) ([][]byte, []int, error) {
+ buf, err := d.readInts(n, 16)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // read string data table
+ data, err := d.readBytes(sz)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // align
+ d.pos += d.pos % 2
+
+ // process
+ s := make([][]byte, n)
+ var m []int
+ for i := 0; i < n; i++ {
+ start := buf[i]
+ if start == -2 {
+ m = append(m, i)
+ } else if start >= 0 {
+ if end := findNull(data, start); end != -1 {
+ s[i] = data[start:end]
+ } else {
+ return nil, nil, ErrInvalidStringTable
+ }
+ }
+ }
+
+ return s, m, nil
+}
+
+// readStrings reads the next n strings and processes the string data table of
+// length sz.
+func (d *decoder) readStrings(n, sz int) (map[int][]byte, map[int]bool, error) {
+ s, m, err := d.readStringTable(n, sz)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ strs := make(map[int][]byte)
+ for k, v := range s {
+ if k == AcsChars {
+ v = canonicalizeAscChars(v)
+ }
+ strs[k] = v
+ }
+
+ strsM := make(map[int]bool, len(m))
+ for _, k := range m {
+ strsM[k] = true
+ }
+
+ return strs, strsM, nil
+}
+
+// canonicalizeAscChars reorders chars to be unique, in order.
+//
+// see repair_ascc in ncurses-6.0/progs/dump_entry.c
+func canonicalizeAscChars(z []byte) []byte {
+ var c chars
+ enc := make(map[byte]byte, len(z)/2)
+ for i := 0; i < len(z); i += 2 {
+ if _, ok := enc[z[i]]; !ok {
+ a, b := z[i], z[i+1]
+ //log.Printf(">>> a: %d %c, b: %d %c", a, a, b, b)
+ c, enc[a] = append(c, b), b
+ }
+ }
+ sort.Sort(c)
+
+ r := make([]byte, 2*len(c))
+ for i := 0; i < len(c); i++ {
+ r[i*2], r[i*2+1] = c[i], enc[c[i]]
+ }
+ return r
+}
+
+type chars []byte
+
+func (c chars) Len() int { return len(c) }
+func (c chars) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
+func (c chars) Less(i, j int) bool { return c[i] < c[j] }