func (ti *Terminfo) ExtStringCaps() map[string][]byte {
	return ti.stringCaps(StringCapName, true)
}
ExtStringCaps returns all extended string capabilities.
package terminfo
import (
	"io"
	"io/ioutil"
	"path"
	"strconv"
	"strings"
)
type Error string
func (err Error) Error() string {
	return string(err)
}
const (
	ErrInvalidFileSize Error = "invalid file size"
	ErrUnexpectedFileEnd Error = "unexpected file end"
	ErrInvalidStringTable Error = "invalid string table"
	ErrInvalidMagic Error = "invalid magic"
	ErrInvalidHeader Error = "invalid header"
	ErrInvalidNames Error = "invalid names"
	ErrInvalidExtendedHeader Error = "invalid extended header"
	ErrEmptyTermName Error = "empty term name"
	ErrDatabaseDirectoryNotFound Error = "database directory not found"
	ErrFileNotFound Error = "file not found"
	ErrInvalidTermProgramVersion Error = "invalid TERM_PROGRAM_VERSION"
)
type Terminfo struct {
	File string
	Names []string
	Bools map[int]bool
	BoolsM map[int]bool
	Nums map[int]int
	NumsM map[int]bool
	Strings map[int][]byte
	StringsM map[int]bool
	ExtBools map[int]bool
	ExtBoolNames map[int][]byte
	ExtNums map[int]int
	ExtNumNames map[int][]byte
	ExtStrings map[int][]byte
	ExtStringNames map[int][]byte
}
func Decode(buf []byte) (*Terminfo, error) {
	var err error
	if len(buf) >= maxFileLength {
		return nil, ErrInvalidFileSize
	}
	d := &decoder{
		buf: buf,
		len: len(buf),
	}
	h, err := d.readInts(6, 16)
	if err != nil {
		return nil, err
	}
	var numWidth int
	if h[fieldMagic] == magic {
		numWidth = 16
	} else if h[fieldMagic] == magicExtended {
		numWidth = 32
	} else {
		return nil, ErrInvalidMagic
	}
	if hasInvalidCaps(h) {
		return nil, ErrInvalidHeader
	}
	if d.len-d.pos < capLength(h) {
		return nil, ErrUnexpectedFileEnd
	}
	names, err := d.readBytes(h[fieldNameSize])
	if err != nil {
		return nil, err
	}
	i := findNull(names, 0)
	if i == -1 {
		return nil, ErrInvalidNames
	}
	names = names[:i]
	bools, boolsM, err := d.readBools(h[fieldBoolCount])
	if err != nil {
		return nil, err
	}
	nums, numsM, err := d.readNums(h[fieldNumCount], numWidth)
	if err != nil {
		return nil, err
	}
	strs, strsM, err := d.readStrings(h[fieldStringCount], h[fieldTableSize])
	if err != nil {
		return nil, err
	}
	ti := &Terminfo{
		Names:    strings.Split(string(names), "|"),
		Bools:    bools,
		BoolsM:   boolsM,
		Nums:     nums,
		NumsM:    numsM,
		Strings:  strs,
		StringsM: strsM,
	}
	if d.pos >= d.len {
		return ti, nil
	}
	eh, err := d.readInts(5, 16)
	if err != nil {
		return nil, err
	}
	if hasInvalidExtOffset(eh) {
		return nil, ErrInvalidExtendedHeader
	}
	if d.len-d.pos != extCapLength(eh, numWidth) {
		return nil, ErrInvalidExtendedHeader
	}
	ti.ExtBools, _, err = d.readBools(eh[fieldExtBoolCount])
	if err != nil {
		return nil, err
	}
	ti.ExtNums, _, err = d.readNums(eh[fieldExtNumCount], numWidth)
	if err != nil {
		return nil, err
	}
	extIndexes, err := d.readInts(eh[fieldExtOffsetCount], 16)
	if err != nil {
		return nil, err
	}
	extData, err := d.readBytes(eh[fieldExtTableSize])
	if err != nil {
		return nil, err
	}
	if d.pos != d.len {
		return nil, ErrUnexpectedFileEnd
	}
	var last int
	ti.ExtStrings, last, err = readStrings(extIndexes, extData, eh[fieldExtStringCount])
	if err != nil {
		return nil, err
	}
	extIndexes, extData = extIndexes[eh[fieldExtStringCount]:], extData[last:]
	ti.ExtBoolNames, _, err = readStrings(extIndexes, extData, eh[fieldExtBoolCount])
	if err != nil {
		return nil, err
	}
	extIndexes = extIndexes[eh[fieldExtBoolCount]:]
	ti.ExtNumNames, _, err = readStrings(extIndexes, extData, eh[fieldExtNumCount])
	if err != nil {
		return nil, err
	}
	extIndexes = extIndexes[eh[fieldExtNumCount]:]
	ti.ExtStringNames, _, err = readStrings(extIndexes, extData, eh[fieldExtStringCount])
	if err != nil {
		return nil, err
	}
	return ti, nil
}
func Open(dir, name string) (*Terminfo, error) {
	var err error
	var buf []byte
	var filename string
	for _, f := range []string{
		path.Join(dir, name[0:1], name),
		path.Join(dir, strconv.FormatUint(uint64(name[0]), 16), name),
	} {
		buf, err = ioutil.ReadFile(f)
		if err == nil {
			filename = f
			break
		}
	}
	if buf == nil {
		return nil, ErrFileNotFound
	}
	ti, err := Decode(buf)
	if err != nil {
		return nil, err
	}
	ti.File = filename
	termCache.Lock()
	for _, n := range ti.Names {
		termCache.db[n] = ti
	}
	termCache.Unlock()
	return ti, nil
}
func (ti *Terminfo) boolCaps(f func(int) string, extended bool) map[string]bool {
	m := make(map[string]bool, len(ti.Bools)+len(ti.ExtBools))
	if !extended {
		for k, v := range ti.Bools {
			m[f(k)] = v
		}
	} else {
		for k, v := range ti.ExtBools {
			m[string(ti.ExtBoolNames[k])] = v
		}
	}
	return m
}
func (ti *Terminfo) BoolCaps() map[string]bool {
	return ti.boolCaps(BoolCapName, false)
}
func (ti *Terminfo) BoolCapsShort() map[string]bool {
	return ti.boolCaps(BoolCapNameShort, false)
}
func (ti *Terminfo) ExtBoolCaps() map[string]bool {
	return ti.boolCaps(BoolCapName, true)
}
func (ti *Terminfo) ExtBoolCapsShort() map[string]bool {
	return ti.boolCaps(BoolCapNameShort, true)
}
func (ti *Terminfo) numCaps(f func(int) string, extended bool) map[string]int {
	m := make(map[string]int, len(ti.Nums)+len(ti.ExtNums))
	if !extended {
		for k, v := range ti.Nums {
			m[f(k)] = v
		}
	} else {
		for k, v := range ti.ExtNums {
			m[string(ti.ExtNumNames[k])] = v
		}
	}
	return m
}
func (ti *Terminfo) NumCaps() map[string]int {
	return ti.numCaps(NumCapName, false)
}
func (ti *Terminfo) NumCapsShort() map[string]int {
	return ti.numCaps(NumCapNameShort, false)
}
func (ti *Terminfo) ExtNumCaps() map[string]int {
	return ti.numCaps(NumCapName, true)
}
func (ti *Terminfo) ExtNumCapsShort() map[string]int {
	return ti.numCaps(NumCapNameShort, true)
}
func (ti *Terminfo) stringCaps(f func(int) string, extended bool) map[string][]byte {
	m := make(map[string][]byte, len(ti.Strings)+len(ti.ExtStrings))
	if !extended {
		for k, v := range ti.Strings {
			m[f(k)] = v
		}
	} else {
		for k, v := range ti.ExtStrings {
			m[string(ti.ExtStringNames[k])] = v
		}
	}
	return m
}
func (ti *Terminfo) StringCaps() map[string][]byte {
	return ti.stringCaps(StringCapName, false)
}
func (ti *Terminfo) StringCapsShort() map[string][]byte {
	return ti.stringCaps(StringCapNameShort, false)
}