Add go vendor

This commit is contained in:
Caleb Bassi 2019-01-14 20:18:13 -08:00
parent 950c769677
commit fce8f0ba62
559 changed files with 197115 additions and 0 deletions

39
vendor/github.com/DHowett/go-plist/.gitlab-ci.yml generated vendored Normal file
View File

@ -0,0 +1,39 @@
image: golang:alpine
stages:
- test
variables:
GO_PACKAGE: "howett.net/plist"
before_script:
- "mkdir -p $(dirname $GOPATH/src/$GO_PACKAGE)"
- "ln -s $(pwd) $GOPATH/src/$GO_PACKAGE"
- "cd $GOPATH/src/$GO_PACKAGE"
.template:go-test: &template-go-test
stage: test
script:
- go test
go-test-cover:latest:
stage: test
script:
- go test -v -cover
coverage: '/^coverage: \d+\.\d+/'
go-test-appengine:latest:
stage: test
script:
- go test -tags appengine
go-test:1.6:
<<: *template-go-test
image: golang:1.6-alpine
go-test:1.4:
<<: *template-go-test
image: golang:1.4-alpine
go-test:1.2:
<<: *template-go-test
image: golang:1.2

58
vendor/github.com/DHowett/go-plist/LICENSE generated vendored Normal file
View File

@ -0,0 +1,58 @@
Copyright (c) 2013, Dustin L. Howett. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
--------------------------------------------------------------------------------
Parts of this package were made available under the license covering
the Go language and all attended core libraries. That license follows.
--------------------------------------------------------------------------------
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

21
vendor/github.com/DHowett/go-plist/README.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
# plist - A pure Go property list transcoder [![coverage report](https://gitlab.howett.net/go/plist/badges/master/coverage.svg)](https://gitlab.howett.net/go/plist/commits/master)
## INSTALL
```
$ go get howett.net/plist
```
## FEATURES
* Supports encoding/decoding property lists (Apple XML, Apple Binary, OpenStep and GNUStep) from/to arbitrary Go types
## USE
```go
package main
import (
"howett.net/plist"
"os"
)
func main() {
encoder := plist.NewEncoder(os.Stdout)
encoder.Encode(map[string]string{"hello": "world"})
}
```

26
vendor/github.com/DHowett/go-plist/bplist.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
package plist
type bplistTrailer struct {
Unused [5]uint8
SortVersion uint8
OffsetIntSize uint8
ObjectRefSize uint8
NumObjects uint64
TopObject uint64
OffsetTableOffset uint64
}
const (
bpTagNull uint8 = 0x00
bpTagBoolFalse = 0x08
bpTagBoolTrue = 0x09
bpTagInteger = 0x10
bpTagReal = 0x20
bpTagDate = 0x30
bpTagData = 0x40
bpTagASCIIString = 0x50
bpTagUTF16String = 0x60
bpTagUID = 0x80
bpTagArray = 0xA0
bpTagDictionary = 0xD0
)

303
vendor/github.com/DHowett/go-plist/bplist_generator.go generated vendored Normal file
View File

@ -0,0 +1,303 @@
package plist
import (
"encoding/binary"
"errors"
"fmt"
"io"
"time"
"unicode/utf16"
)
func bplistMinimumIntSize(n uint64) int {
switch {
case n <= uint64(0xff):
return 1
case n <= uint64(0xffff):
return 2
case n <= uint64(0xffffffff):
return 4
default:
return 8
}
}
func bplistValueShouldUnique(pval cfValue) bool {
switch pval.(type) {
case cfString, *cfNumber, *cfReal, cfDate, cfData:
return true
}
return false
}
type bplistGenerator struct {
writer *countedWriter
objmap map[interface{}]uint64 // maps pValue.hash()es to object locations
objtable []cfValue
trailer bplistTrailer
}
func (p *bplistGenerator) flattenPlistValue(pval cfValue) {
key := pval.hash()
if bplistValueShouldUnique(pval) {
if _, ok := p.objmap[key]; ok {
return
}
}
p.objmap[key] = uint64(len(p.objtable))
p.objtable = append(p.objtable, pval)
switch pval := pval.(type) {
case *cfDictionary:
pval.sort()
for _, k := range pval.keys {
p.flattenPlistValue(cfString(k))
}
for _, v := range pval.values {
p.flattenPlistValue(v)
}
case *cfArray:
for _, v := range pval.values {
p.flattenPlistValue(v)
}
}
}
func (p *bplistGenerator) indexForPlistValue(pval cfValue) (uint64, bool) {
v, ok := p.objmap[pval.hash()]
return v, ok
}
func (p *bplistGenerator) generateDocument(root cfValue) {
p.objtable = make([]cfValue, 0, 16)
p.objmap = make(map[interface{}]uint64)
p.flattenPlistValue(root)
p.trailer.NumObjects = uint64(len(p.objtable))
p.trailer.ObjectRefSize = uint8(bplistMinimumIntSize(p.trailer.NumObjects))
p.writer.Write([]byte("bplist00"))
offtable := make([]uint64, p.trailer.NumObjects)
for i, pval := range p.objtable {
offtable[i] = uint64(p.writer.BytesWritten())
p.writePlistValue(pval)
}
p.trailer.OffsetIntSize = uint8(bplistMinimumIntSize(uint64(p.writer.BytesWritten())))
p.trailer.TopObject = p.objmap[root.hash()]
p.trailer.OffsetTableOffset = uint64(p.writer.BytesWritten())
for _, offset := range offtable {
p.writeSizedInt(offset, int(p.trailer.OffsetIntSize))
}
binary.Write(p.writer, binary.BigEndian, p.trailer)
}
func (p *bplistGenerator) writePlistValue(pval cfValue) {
if pval == nil {
return
}
switch pval := pval.(type) {
case *cfDictionary:
p.writeDictionaryTag(pval)
case *cfArray:
p.writeArrayTag(pval.values)
case cfString:
p.writeStringTag(string(pval))
case *cfNumber:
p.writeIntTag(pval.signed, pval.value)
case *cfReal:
if pval.wide {
p.writeRealTag(pval.value, 64)
} else {
p.writeRealTag(pval.value, 32)
}
case cfBoolean:
p.writeBoolTag(bool(pval))
case cfData:
p.writeDataTag([]byte(pval))
case cfDate:
p.writeDateTag(time.Time(pval))
case cfUID:
p.writeUIDTag(UID(pval))
default:
panic(fmt.Errorf("unknown plist type %t", pval))
}
}
func (p *bplistGenerator) writeSizedInt(n uint64, nbytes int) {
var val interface{}
switch nbytes {
case 1:
val = uint8(n)
case 2:
val = uint16(n)
case 4:
val = uint32(n)
case 8:
val = n
default:
panic(errors.New("illegal integer size"))
}
binary.Write(p.writer, binary.BigEndian, val)
}
func (p *bplistGenerator) writeBoolTag(v bool) {
tag := uint8(bpTagBoolFalse)
if v {
tag = bpTagBoolTrue
}
binary.Write(p.writer, binary.BigEndian, tag)
}
func (p *bplistGenerator) writeIntTag(signed bool, n uint64) {
var tag uint8
var val interface{}
switch {
case n <= uint64(0xff):
val = uint8(n)
tag = bpTagInteger | 0x0
case n <= uint64(0xffff):
val = uint16(n)
tag = bpTagInteger | 0x1
case n <= uint64(0xffffffff):
val = uint32(n)
tag = bpTagInteger | 0x2
case n > uint64(0x7fffffffffffffff) && !signed:
// 64-bit values are always *signed* in format 00.
// Any unsigned value that doesn't intersect with the signed
// range must be sign-extended and stored as a SInt128
val = n
tag = bpTagInteger | 0x4
default:
val = n
tag = bpTagInteger | 0x3
}
binary.Write(p.writer, binary.BigEndian, tag)
if tag&0xF == 0x4 {
// SInt128; in the absence of true 128-bit integers in Go,
// we'll just fake the top half. We only got here because
// we had an unsigned 64-bit int that didn't fit,
// so sign extend it with zeroes.
binary.Write(p.writer, binary.BigEndian, uint64(0))
}
binary.Write(p.writer, binary.BigEndian, val)
}
func (p *bplistGenerator) writeUIDTag(u UID) {
nbytes := bplistMinimumIntSize(uint64(u))
tag := uint8(bpTagUID | (nbytes - 1))
binary.Write(p.writer, binary.BigEndian, tag)
p.writeSizedInt(uint64(u), nbytes)
}
func (p *bplistGenerator) writeRealTag(n float64, bits int) {
var tag uint8 = bpTagReal | 0x3
var val interface{} = n
if bits == 32 {
val = float32(n)
tag = bpTagReal | 0x2
}
binary.Write(p.writer, binary.BigEndian, tag)
binary.Write(p.writer, binary.BigEndian, val)
}
func (p *bplistGenerator) writeDateTag(t time.Time) {
tag := uint8(bpTagDate) | 0x3
val := float64(t.In(time.UTC).UnixNano()) / float64(time.Second)
val -= 978307200 // Adjust to Apple Epoch
binary.Write(p.writer, binary.BigEndian, tag)
binary.Write(p.writer, binary.BigEndian, val)
}
func (p *bplistGenerator) writeCountedTag(tag uint8, count uint64) {
marker := tag
if count >= 0xF {
marker |= 0xF
} else {
marker |= uint8(count)
}
binary.Write(p.writer, binary.BigEndian, marker)
if count >= 0xF {
p.writeIntTag(false, count)
}
}
func (p *bplistGenerator) writeDataTag(data []byte) {
p.writeCountedTag(bpTagData, uint64(len(data)))
binary.Write(p.writer, binary.BigEndian, data)
}
func (p *bplistGenerator) writeStringTag(str string) {
for _, r := range str {
if r > 0x7F {
utf16Runes := utf16.Encode([]rune(str))
p.writeCountedTag(bpTagUTF16String, uint64(len(utf16Runes)))
binary.Write(p.writer, binary.BigEndian, utf16Runes)
return
}
}
p.writeCountedTag(bpTagASCIIString, uint64(len(str)))
binary.Write(p.writer, binary.BigEndian, []byte(str))
}
func (p *bplistGenerator) writeDictionaryTag(dict *cfDictionary) {
// assumption: sorted already; flattenPlistValue did this.
cnt := len(dict.keys)
p.writeCountedTag(bpTagDictionary, uint64(cnt))
vals := make([]uint64, cnt*2)
for i, k := range dict.keys {
// invariant: keys have already been "uniqued" (as PStrings)
keyIdx, ok := p.objmap[cfString(k).hash()]
if !ok {
panic(errors.New("failed to find key " + k + " in object map during serialization"))
}
vals[i] = keyIdx
}
for i, v := range dict.values {
// invariant: values have already been "uniqued"
objIdx, ok := p.indexForPlistValue(v)
if !ok {
panic(errors.New("failed to find value in object map during serialization"))
}
vals[i+cnt] = objIdx
}
for _, v := range vals {
p.writeSizedInt(v, int(p.trailer.ObjectRefSize))
}
}
func (p *bplistGenerator) writeArrayTag(arr []cfValue) {
p.writeCountedTag(bpTagArray, uint64(len(arr)))
for _, v := range arr {
objIdx, ok := p.indexForPlistValue(v)
if !ok {
panic(errors.New("failed to find value in object map during serialization"))
}
p.writeSizedInt(objIdx, int(p.trailer.ObjectRefSize))
}
}
func (p *bplistGenerator) Indent(i string) {
// There's nothing to indent.
}
func newBplistGenerator(w io.Writer) *bplistGenerator {
return &bplistGenerator{
writer: &countedWriter{Writer: mustWriter{w}},
}
}

353
vendor/github.com/DHowett/go-plist/bplist_parser.go generated vendored Normal file
View File

@ -0,0 +1,353 @@
package plist
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"runtime"
"time"
"unicode/utf16"
)
const (
signedHighBits = 0xFFFFFFFFFFFFFFFF
)
type offset uint64
type bplistParser struct {
buffer []byte
reader io.ReadSeeker
version int
objects []cfValue // object ID to object
trailer bplistTrailer
trailerOffset uint64
containerStack []offset // slice of object offsets; manipulated during container deserialization
}
func (p *bplistParser) validateDocumentTrailer() {
if p.trailer.OffsetTableOffset >= p.trailerOffset {
panic(fmt.Errorf("offset table beyond beginning of trailer (0x%x, trailer@0x%x)", p.trailer.OffsetTableOffset, p.trailerOffset))
}
if p.trailer.OffsetTableOffset < 9 {
panic(fmt.Errorf("offset table begins inside header (0x%x)", p.trailer.OffsetTableOffset))
}
if p.trailerOffset > (p.trailer.NumObjects*uint64(p.trailer.OffsetIntSize))+p.trailer.OffsetTableOffset {
panic(errors.New("garbage between offset table and trailer"))
}
if p.trailer.OffsetTableOffset+(uint64(p.trailer.OffsetIntSize)*p.trailer.NumObjects) > p.trailerOffset {
panic(errors.New("offset table isn't long enough to address every object"))
}
maxObjectRef := uint64(1) << (8 * p.trailer.ObjectRefSize)
if p.trailer.NumObjects > maxObjectRef {
panic(fmt.Errorf("more objects (%v) than object ref size (%v bytes) can support", p.trailer.NumObjects, p.trailer.ObjectRefSize))
}
if p.trailer.OffsetIntSize < uint8(8) && (uint64(1)<<(8*p.trailer.OffsetIntSize)) <= p.trailer.OffsetTableOffset {
panic(errors.New("offset size isn't big enough to address entire file"))
}
if p.trailer.TopObject >= p.trailer.NumObjects {
panic(fmt.Errorf("top object #%d is out of range (only %d exist)", p.trailer.TopObject, p.trailer.NumObjects))
}
}
func (p *bplistParser) parseDocument() (pval cfValue, parseError error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
parseError = plistParseError{"binary", r.(error)}
}
}()
p.buffer, _ = ioutil.ReadAll(p.reader)
l := len(p.buffer)
if l < 40 {
panic(errors.New("not enough data"))
}
if !bytes.Equal(p.buffer[0:6], []byte{'b', 'p', 'l', 'i', 's', 't'}) {
panic(errors.New("incomprehensible magic"))
}
p.version = int(((p.buffer[6] - '0') * 10) + (p.buffer[7] - '0'))
if p.version > 1 {
panic(fmt.Errorf("unexpected version %d", p.version))
}
p.trailerOffset = uint64(l - 32)
p.trailer = bplistTrailer{
SortVersion: p.buffer[p.trailerOffset+5],
OffsetIntSize: p.buffer[p.trailerOffset+6],
ObjectRefSize: p.buffer[p.trailerOffset+7],
NumObjects: binary.BigEndian.Uint64(p.buffer[p.trailerOffset+8:]),
TopObject: binary.BigEndian.Uint64(p.buffer[p.trailerOffset+16:]),
OffsetTableOffset: binary.BigEndian.Uint64(p.buffer[p.trailerOffset+24:]),
}
p.validateDocumentTrailer()
// INVARIANTS:
// - Entire offset table is before trailer
// - Offset table begins after header
// - Offset table can address entire document
// - Object IDs are big enough to support the number of objects in this plist
// - Top object is in range
p.objects = make([]cfValue, p.trailer.NumObjects)
pval = p.objectAtIndex(p.trailer.TopObject)
return
}
// parseSizedInteger returns a 128-bit integer as low64, high64
func (p *bplistParser) parseSizedInteger(off offset, nbytes int) (lo uint64, hi uint64, newOffset offset) {
// Per comments in CoreFoundation, format version 00 requires that all
// 1, 2 or 4-byte integers be interpreted as unsigned. 8-byte integers are
// signed (always?) and therefore must be sign extended here.
// negative 1, 2, or 4-byte integers are always emitted as 64-bit.
switch nbytes {
case 1:
lo, hi = uint64(p.buffer[off]), 0
case 2:
lo, hi = uint64(binary.BigEndian.Uint16(p.buffer[off:])), 0
case 4:
lo, hi = uint64(binary.BigEndian.Uint32(p.buffer[off:])), 0
case 8:
lo = binary.BigEndian.Uint64(p.buffer[off:])
if p.buffer[off]&0x80 != 0 {
// sign extend if lo is signed
hi = signedHighBits
}
case 16:
lo, hi = binary.BigEndian.Uint64(p.buffer[off+8:]), binary.BigEndian.Uint64(p.buffer[off:])
default:
panic(errors.New("illegal integer size"))
}
newOffset = off + offset(nbytes)
return
}
func (p *bplistParser) parseObjectRefAtOffset(off offset) (uint64, offset) {
oid, _, next := p.parseSizedInteger(off, int(p.trailer.ObjectRefSize))
return oid, next
}
func (p *bplistParser) parseOffsetAtOffset(off offset) (offset, offset) {
parsedOffset, _, next := p.parseSizedInteger(off, int(p.trailer.OffsetIntSize))
return offset(parsedOffset), next
}
func (p *bplistParser) objectAtIndex(index uint64) cfValue {
if index >= p.trailer.NumObjects {
panic(fmt.Errorf("invalid object#%d (max %d)", index, p.trailer.NumObjects))
}
if pval := p.objects[index]; pval != nil {
return pval
}
off, _ := p.parseOffsetAtOffset(offset(p.trailer.OffsetTableOffset + (index * uint64(p.trailer.OffsetIntSize))))
if off > offset(p.trailer.OffsetTableOffset-1) {
panic(fmt.Errorf("object#%d starts beyond beginning of object table (0x%x, table@0x%x)", index, off, p.trailer.OffsetTableOffset))
}
pval := p.parseTagAtOffset(off)
p.objects[index] = pval
return pval
}
func (p *bplistParser) pushNestedObject(off offset) {
for _, v := range p.containerStack {
if v == off {
p.panicNestedObject(off)
}
}
p.containerStack = append(p.containerStack, off)
}
func (p *bplistParser) panicNestedObject(off offset) {
ids := ""
for _, v := range p.containerStack {
ids += fmt.Sprintf("0x%x > ", v)
}
// %s0x%d: ids above ends with " > "
panic(fmt.Errorf("self-referential collection@0x%x (%s0x%x) cannot be deserialized", off, ids, off))
}
func (p *bplistParser) popNestedObject() {
p.containerStack = p.containerStack[:len(p.containerStack)-1]
}
func (p *bplistParser) parseTagAtOffset(off offset) cfValue {
tag := p.buffer[off]
switch tag & 0xF0 {
case bpTagNull:
switch tag & 0x0F {
case bpTagBoolTrue, bpTagBoolFalse:
return cfBoolean(tag == bpTagBoolTrue)
}
case bpTagInteger:
lo, hi, _ := p.parseIntegerAtOffset(off)
return &cfNumber{
signed: hi == signedHighBits, // a signed integer is stored as a 128-bit integer with the top 64 bits set
value: lo,
}
case bpTagReal:
nbytes := 1 << (tag & 0x0F)
switch nbytes {
case 4:
bits := binary.BigEndian.Uint32(p.buffer[off+1:])
return &cfReal{wide: false, value: float64(math.Float32frombits(bits))}
case 8:
bits := binary.BigEndian.Uint64(p.buffer[off+1:])
return &cfReal{wide: true, value: math.Float64frombits(bits)}
}
panic(errors.New("illegal float size"))
case bpTagDate:
bits := binary.BigEndian.Uint64(p.buffer[off+1:])
val := math.Float64frombits(bits)
// Apple Epoch is 20110101000000Z
// Adjust for UNIX Time
val += 978307200
sec, fsec := math.Modf(val)
time := time.Unix(int64(sec), int64(fsec*float64(time.Second))).In(time.UTC)
return cfDate(time)
case bpTagData:
data := p.parseDataAtOffset(off)
return cfData(data)
case bpTagASCIIString:
str := p.parseASCIIStringAtOffset(off)
return cfString(str)
case bpTagUTF16String:
str := p.parseUTF16StringAtOffset(off)
return cfString(str)
case bpTagUID: // Somehow different than int: low half is nbytes - 1 instead of log2(nbytes)
lo, _, _ := p.parseSizedInteger(off+1, int(tag&0xF)+1)
return cfUID(lo)
case bpTagDictionary:
return p.parseDictionaryAtOffset(off)
case bpTagArray:
return p.parseArrayAtOffset(off)
}
panic(fmt.Errorf("unexpected atom 0x%2.02x at offset 0x%x", tag, off))
}
func (p *bplistParser) parseIntegerAtOffset(off offset) (uint64, uint64, offset) {
tag := p.buffer[off]
return p.parseSizedInteger(off+1, 1<<(tag&0xF))
}
func (p *bplistParser) countForTagAtOffset(off offset) (uint64, offset) {
tag := p.buffer[off]
cnt := uint64(tag & 0x0F)
if cnt == 0xF {
cnt, _, off = p.parseIntegerAtOffset(off + 1)
return cnt, off
}
return cnt, off + 1
}
func (p *bplistParser) parseDataAtOffset(off offset) []byte {
len, start := p.countForTagAtOffset(off)
if start+offset(len) > offset(p.trailer.OffsetTableOffset) {
panic(fmt.Errorf("data@0x%x too long (%v bytes, max is %v)", off, len, p.trailer.OffsetTableOffset-uint64(start)))
}
return p.buffer[start : start+offset(len)]
}
func (p *bplistParser) parseASCIIStringAtOffset(off offset) string {
len, start := p.countForTagAtOffset(off)
if start+offset(len) > offset(p.trailer.OffsetTableOffset) {
panic(fmt.Errorf("ascii string@0x%x too long (%v bytes, max is %v)", off, len, p.trailer.OffsetTableOffset-uint64(start)))
}
return zeroCopy8BitString(p.buffer, int(start), int(len))
}
func (p *bplistParser) parseUTF16StringAtOffset(off offset) string {
len, start := p.countForTagAtOffset(off)
bytes := len * 2
if start+offset(bytes) > offset(p.trailer.OffsetTableOffset) {
panic(fmt.Errorf("utf16 string@0x%x too long (%v bytes, max is %v)", off, bytes, p.trailer.OffsetTableOffset-uint64(start)))
}
u16s := make([]uint16, len)
for i := offset(0); i < offset(len); i++ {
u16s[i] = binary.BigEndian.Uint16(p.buffer[start+(i*2):])
}
runes := utf16.Decode(u16s)
return string(runes)
}
func (p *bplistParser) parseObjectListAtOffset(off offset, count uint64) []cfValue {
if off+offset(count*uint64(p.trailer.ObjectRefSize)) > offset(p.trailer.OffsetTableOffset) {
panic(fmt.Errorf("list@0x%x length (%v) puts its end beyond the offset table at 0x%x", off, count, p.trailer.OffsetTableOffset))
}
objects := make([]cfValue, count)
next := off
var oid uint64
for i := uint64(0); i < count; i++ {
oid, next = p.parseObjectRefAtOffset(next)
objects[i] = p.objectAtIndex(oid)
}
return objects
}
func (p *bplistParser) parseDictionaryAtOffset(off offset) *cfDictionary {
p.pushNestedObject(off)
defer p.popNestedObject()
// a dictionary is an object list of [key key key val val val]
cnt, start := p.countForTagAtOffset(off)
objects := p.parseObjectListAtOffset(start, cnt*2)
keys := make([]string, cnt)
for i := uint64(0); i < cnt; i++ {
if str, ok := objects[i].(cfString); ok {
keys[i] = string(str)
} else {
panic(fmt.Errorf("dictionary@0x%x contains non-string key at index %d", off, i))
}
}
return &cfDictionary{
keys: keys,
values: objects[cnt:],
}
}
func (p *bplistParser) parseArrayAtOffset(off offset) *cfArray {
p.pushNestedObject(off)
defer p.popNestedObject()
// an array is just an object list
cnt, start := p.countForTagAtOffset(off)
return &cfArray{p.parseObjectListAtOffset(start, cnt)}
}
func newBplistParser(r io.ReadSeeker) *bplistParser {
return &bplistParser{reader: r}
}

119
vendor/github.com/DHowett/go-plist/decode.go generated vendored Normal file
View File

@ -0,0 +1,119 @@
package plist
import (
"bytes"
"io"
"reflect"
"runtime"
)
type parser interface {
parseDocument() (cfValue, error)
}
// A Decoder reads a property list from an input stream.
type Decoder struct {
// the format of the most-recently-decoded property list
Format int
reader io.ReadSeeker
lax bool
}
// Decode works like Unmarshal, except it reads the decoder stream to find property list elements.
//
// After Decoding, the Decoder's Format field will be set to one of the plist format constants.
func (p *Decoder) Decode(v interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
err = r.(error)
}
}()
header := make([]byte, 6)
p.reader.Read(header)
p.reader.Seek(0, 0)
var parser parser
var pval cfValue
if bytes.Equal(header, []byte("bplist")) {
parser = newBplistParser(p.reader)
pval, err = parser.parseDocument()
if err != nil {
// Had a bplist header, but still got an error: we have to die here.
return err
}
p.Format = BinaryFormat
} else {
parser = newXMLPlistParser(p.reader)
pval, err = parser.parseDocument()
if _, ok := err.(invalidPlistError); ok {
// Rewind: the XML parser might have exhausted the file.
p.reader.Seek(0, 0)
// We don't use parser here because we want the textPlistParser type
tp := newTextPlistParser(p.reader)
pval, err = tp.parseDocument()
if err != nil {
return err
}
p.Format = tp.format
if p.Format == OpenStepFormat {
// OpenStep property lists can only store strings,
// so we have to turn on lax mode here for the unmarshal step later.
p.lax = true
}
} else {
if err != nil {
return err
}
p.Format = XMLFormat
}
}
p.unmarshal(pval, reflect.ValueOf(v))
return
}
// NewDecoder returns a Decoder that reads property list elements from a stream reader, r.
// NewDecoder requires a Seekable stream for the purposes of file type detection.
func NewDecoder(r io.ReadSeeker) *Decoder {
return &Decoder{Format: InvalidFormat, reader: r, lax: false}
}
// Unmarshal parses a property list document and stores the result in the value pointed to by v.
//
// Unmarshal uses the inverse of the type encodings that Marshal uses, allocating heap-borne types as necessary.
//
// When given a nil pointer, Unmarshal allocates a new value for it to point to.
//
// To decode property list values into an interface value, Unmarshal decodes the property list into the concrete value contained
// in the interface value. If the interface value is nil, Unmarshal stores one of the following in the interface value:
//
// string, bool, uint64, float64
// plist.UID for "CoreFoundation Keyed Archiver UIDs" (convertible to uint64)
// []byte, for plist data
// []interface{}, for plist arrays
// map[string]interface{}, for plist dictionaries
//
// If a property list value is not appropriate for a given value type, Unmarshal aborts immediately and returns an error.
//
// As Go does not support 128-bit types, and we don't want to pretend we're giving the user integer types (as opposed to
// secretly passing them structs), Unmarshal will drop the high 64 bits of any 128-bit integers encoded in binary property lists.
// (This is important because CoreFoundation serializes some large 64-bit values as 128-bit values with an empty high half.)
//
// When Unmarshal encounters an OpenStep property list, it will enter a relaxed parsing mode: OpenStep property lists can only store
// plain old data as strings, so we will attempt to recover integer, floating-point, boolean and date values wherever they are necessary.
// (for example, if Unmarshal attempts to unmarshal an OpenStep property list into a time.Time, it will try to parse the string it
// receives as a time.)
//
// Unmarshal returns the detected property list format and an error, if any.
func Unmarshal(data []byte, v interface{}) (format int, err error) {
r := bytes.NewReader(data)
dec := NewDecoder(r)
err = dec.Decode(v)
format = dec.Format
return
}

5
vendor/github.com/DHowett/go-plist/doc.go generated vendored Normal file
View File

@ -0,0 +1,5 @@
// Package plist implements encoding and decoding of Apple's "property list" format.
// Property lists come in three sorts: plain text (GNUStep and OpenStep), XML and binary.
// plist supports all of them.
// The mapping between property list and Go objects is described in the documentation for the Marshal and Unmarshal functions.
package plist

126
vendor/github.com/DHowett/go-plist/encode.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package plist
import (
"bytes"
"errors"
"io"
"reflect"
"runtime"
)
type generator interface {
generateDocument(cfValue)
Indent(string)
}
// An Encoder writes a property list to an output stream.
type Encoder struct {
writer io.Writer
format int
indent string
}
// Encode writes the property list encoding of v to the stream.
func (p *Encoder) Encode(v interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
err = r.(error)
}
}()
pval := p.marshal(reflect.ValueOf(v))
if pval == nil {
panic(errors.New("plist: no root element to encode"))
}
var g generator
switch p.format {
case XMLFormat:
g = newXMLPlistGenerator(p.writer)
case BinaryFormat, AutomaticFormat:
g = newBplistGenerator(p.writer)
case OpenStepFormat, GNUStepFormat:
g = newTextPlistGenerator(p.writer, p.format)
}
g.Indent(p.indent)
g.generateDocument(pval)
return
}
// Indent turns on pretty-printing for the XML and Text property list formats.
// Each element begins on a new line and is preceded by one or more copies of indent according to its nesting depth.
func (p *Encoder) Indent(indent string) {
p.indent = indent
}
// NewEncoder returns an Encoder that writes an XML property list to w.
func NewEncoder(w io.Writer) *Encoder {
return NewEncoderForFormat(w, XMLFormat)
}
// NewEncoderForFormat returns an Encoder that writes a property list to w in the specified format.
// Pass AutomaticFormat to allow the library to choose the best encoding (currently BinaryFormat).
func NewEncoderForFormat(w io.Writer, format int) *Encoder {
return &Encoder{
writer: w,
format: format,
}
}
// NewBinaryEncoder returns an Encoder that writes a binary property list to w.
func NewBinaryEncoder(w io.Writer) *Encoder {
return NewEncoderForFormat(w, BinaryFormat)
}
// Marshal returns the property list encoding of v in the specified format.
//
// Pass AutomaticFormat to allow the library to choose the best encoding (currently BinaryFormat).
//
// Marshal traverses the value v recursively.
// Any nil values encountered, other than the root, will be silently discarded as
// the property list format bears no representation for nil values.
//
// Strings, integers of varying size, floats and booleans are encoded unchanged.
// Strings bearing non-ASCII runes will be encoded differently depending upon the property list format:
// UTF-8 for XML property lists and UTF-16 for binary property lists.
//
// Slice and Array values are encoded as property list arrays, except for
// []byte values, which are encoded as data.
//
// Map values encode as dictionaries. The map's key type must be string; there is no provision for encoding non-string dictionary keys.
//
// Struct values are encoded as dictionaries, with only exported fields being serialized. Struct field encoding may be influenced with the use of tags.
// The tag format is:
//
// `plist:"<key>[,flags...]"`
//
// The following flags are supported:
//
// omitempty Only include the field if it is not set to the zero value for its type.
//
// If the key is "-", the field is ignored.
//
// Anonymous struct fields are encoded as if their exported fields were exposed via the outer struct.
//
// Pointer values encode as the value pointed to.
//
// Channel, complex and function values cannot be encoded. Any attempt to do so causes Marshal to return an error.
func Marshal(v interface{}, format int) ([]byte, error) {
return MarshalIndent(v, format, "")
}
// MarshalIndent works like Marshal, but each property list element
// begins on a new line and is preceded by one or more copies of indent according to its nesting depth.
func MarshalIndent(v interface{}, format int, indent string) ([]byte, error) {
buf := &bytes.Buffer{}
enc := NewEncoderForFormat(buf, format)
enc.Indent(indent)
if err := enc.Encode(v); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

17
vendor/github.com/DHowett/go-plist/fuzz.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
// +build gofuzz
package plist
import (
"bytes"
)
func Fuzz(data []byte) int {
buf := bytes.NewReader(data)
var obj interface{}
if err := NewDecoder(buf).Decode(&obj); err != nil {
return 0
}
return 1
}

186
vendor/github.com/DHowett/go-plist/marshal.go generated vendored Normal file
View File

@ -0,0 +1,186 @@
package plist
import (
"encoding"
"reflect"
"time"
)
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
var (
plistMarshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
)
func implementsInterface(val reflect.Value, interfaceType reflect.Type) (interface{}, bool) {
if val.CanInterface() && val.Type().Implements(interfaceType) {
return val.Interface(), true
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(interfaceType) {
return pv.Interface(), true
}
}
return nil, false
}
func (p *Encoder) marshalPlistInterface(marshalable Marshaler) cfValue {
value, err := marshalable.MarshalPlist()
if err != nil {
panic(err)
}
return p.marshal(reflect.ValueOf(value))
}
// marshalTextInterface marshals a TextMarshaler to a plist string.
func (p *Encoder) marshalTextInterface(marshalable encoding.TextMarshaler) cfValue {
s, err := marshalable.MarshalText()
if err != nil {
panic(err)
}
return cfString(s)
}
// marshalStruct marshals a reflected struct value to a plist dictionary
func (p *Encoder) marshalStruct(typ reflect.Type, val reflect.Value) cfValue {
tinfo, _ := getTypeInfo(typ)
dict := &cfDictionary{
keys: make([]string, 0, len(tinfo.fields)),
values: make([]cfValue, 0, len(tinfo.fields)),
}
for _, finfo := range tinfo.fields {
value := finfo.value(val)
if !value.IsValid() || finfo.omitEmpty && isEmptyValue(value) {
continue
}
dict.keys = append(dict.keys, finfo.name)
dict.values = append(dict.values, p.marshal(value))
}
return dict
}
func (p *Encoder) marshalTime(val reflect.Value) cfValue {
time := val.Interface().(time.Time)
return cfDate(time)
}
func (p *Encoder) marshal(val reflect.Value) cfValue {
if !val.IsValid() {
return nil
}
if receiver, can := implementsInterface(val, plistMarshalerType); can {
return p.marshalPlistInterface(receiver.(Marshaler))
}
// time.Time implements TextMarshaler, but we need to store it in RFC3339
if val.Type() == timeType {
return p.marshalTime(val)
}
if val.Kind() == reflect.Ptr || (val.Kind() == reflect.Interface && val.NumMethod() == 0) {
ival := val.Elem()
if ival.IsValid() && ival.Type() == timeType {
return p.marshalTime(ival)
}
}
// Check for text marshaler.
if receiver, can := implementsInterface(val, textMarshalerType); can {
return p.marshalTextInterface(receiver.(encoding.TextMarshaler))
}
// Descend into pointers or interfaces
if val.Kind() == reflect.Ptr || (val.Kind() == reflect.Interface && val.NumMethod() == 0) {
val = val.Elem()
}
// We got this far and still may have an invalid anything or nil ptr/interface
if !val.IsValid() || ((val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface) && val.IsNil()) {
return nil
}
typ := val.Type()
if typ == uidType {
return cfUID(val.Uint())
}
if val.Kind() == reflect.Struct {
return p.marshalStruct(typ, val)
}
switch val.Kind() {
case reflect.String:
return cfString(val.String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return &cfNumber{signed: true, value: uint64(val.Int())}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return &cfNumber{signed: false, value: val.Uint()}
case reflect.Float32:
return &cfReal{wide: false, value: val.Float()}
case reflect.Float64:
return &cfReal{wide: true, value: val.Float()}
case reflect.Bool:
return cfBoolean(val.Bool())
case reflect.Slice, reflect.Array:
if typ.Elem().Kind() == reflect.Uint8 {
bytes := []byte(nil)
if val.CanAddr() {
bytes = val.Bytes()
} else {
bytes = make([]byte, val.Len())
reflect.Copy(reflect.ValueOf(bytes), val)
}
return cfData(bytes)
} else {
values := make([]cfValue, val.Len())
for i, length := 0, val.Len(); i < length; i++ {
if subpval := p.marshal(val.Index(i)); subpval != nil {
values[i] = subpval
}
}
return &cfArray{values}
}
case reflect.Map:
if typ.Key().Kind() != reflect.String {
panic(&unknownTypeError{typ})
}
l := val.Len()
dict := &cfDictionary{
keys: make([]string, 0, l),
values: make([]cfValue, 0, l),
}
for _, keyv := range val.MapKeys() {
if subpval := p.marshal(val.MapIndex(keyv)); subpval != nil {
dict.keys = append(dict.keys, keyv.String())
dict.values = append(dict.values, subpval)
}
}
return dict
default:
panic(&unknownTypeError{typ})
}
}

50
vendor/github.com/DHowett/go-plist/must.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
package plist
import (
"io"
"strconv"
)
type mustWriter struct {
io.Writer
}
func (w mustWriter) Write(p []byte) (int, error) {
n, err := w.Writer.Write(p)
if err != nil {
panic(err)
}
return n, nil
}
func mustParseInt(str string, base, bits int) int64 {
i, err := strconv.ParseInt(str, base, bits)
if err != nil {
panic(err)
}
return i
}
func mustParseUint(str string, base, bits int) uint64 {
i, err := strconv.ParseUint(str, base, bits)
if err != nil {
panic(err)
}
return i
}
func mustParseFloat(str string, bits int) float64 {
i, err := strconv.ParseFloat(str, bits)
if err != nil {
panic(err)
}
return i
}
func mustParseBool(str string) bool {
i, err := strconv.ParseBool(str)
if err != nil {
panic(err)
}
return i
}

85
vendor/github.com/DHowett/go-plist/plist.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
package plist
import (
"reflect"
)
// Property list format constants
const (
// Used by Decoder to represent an invalid property list.
InvalidFormat int = 0
// Used to indicate total abandon with regards to Encoder's output format.
AutomaticFormat = 0
XMLFormat = 1
BinaryFormat = 2
OpenStepFormat = 3
GNUStepFormat = 4
)
var FormatNames = map[int]string{
InvalidFormat: "unknown/invalid",
XMLFormat: "XML",
BinaryFormat: "Binary",
OpenStepFormat: "OpenStep",
GNUStepFormat: "GNUStep",
}
type unknownTypeError struct {
typ reflect.Type
}
func (u *unknownTypeError) Error() string {
return "plist: can't marshal value of type " + u.typ.String()
}
type invalidPlistError struct {
format string
err error
}
func (e invalidPlistError) Error() string {
s := "plist: invalid " + e.format + " property list"
if e.err != nil {
s += ": " + e.err.Error()
}
return s
}
type plistParseError struct {
format string
err error
}
func (e plistParseError) Error() string {
s := "plist: error parsing " + e.format + " property list"
if e.err != nil {
s += ": " + e.err.Error()
}
return s
}
// A UID represents a unique object identifier. UIDs are serialized in a manner distinct from
// that of integers.
//
// UIDs cannot be serialized in OpenStepFormat or GNUStepFormat property lists.
type UID uint64
// Marshaler is the interface implemented by types that can marshal themselves into valid
// property list objects. The returned value is marshaled in place of the original value
// implementing Marshaler
//
// If an error is returned by MarshalPlist, marshaling stops and the error is returned.
type Marshaler interface {
MarshalPlist() (interface{}, error)
}
// Unmarshaler is the interface implemented by types that can unmarshal themselves from
// property list objects. The UnmarshalPlist method receives a function that may
// be called to unmarshal the original property list value into a field or variable.
//
// It is safe to call the unmarshal function more than once.
type Unmarshaler interface {
UnmarshalPlist(unmarshal func(interface{}) error) error
}

139
vendor/github.com/DHowett/go-plist/plist_types.go generated vendored Normal file
View File

@ -0,0 +1,139 @@
package plist
import (
"hash/crc32"
"sort"
"time"
)
type cfValue interface {
typeName() string
hash() interface{}
}
type cfDictionary struct {
keys sort.StringSlice
values []cfValue
}
func (*cfDictionary) typeName() string {
return "dictionary"
}
func (p *cfDictionary) hash() interface{} {
return p
}
func (p *cfDictionary) Len() int {
return len(p.keys)
}
func (p *cfDictionary) Less(i, j int) bool {
return p.keys.Less(i, j)
}
func (p *cfDictionary) Swap(i, j int) {
p.keys.Swap(i, j)
p.values[i], p.values[j] = p.values[j], p.values[i]
}
func (p *cfDictionary) sort() {
sort.Sort(p)
}
type cfArray struct {
values []cfValue
}
func (*cfArray) typeName() string {
return "array"
}
func (p *cfArray) hash() interface{} {
return p
}
type cfString string
func (cfString) typeName() string {
return "string"
}
func (p cfString) hash() interface{} {
return string(p)
}
type cfNumber struct {
signed bool
value uint64
}
func (*cfNumber) typeName() string {
return "integer"
}
func (p *cfNumber) hash() interface{} {
if p.signed {
return int64(p.value)
}
return p.value
}
type cfReal struct {
wide bool
value float64
}
func (cfReal) typeName() string {
return "real"
}
func (p *cfReal) hash() interface{} {
if p.wide {
return p.value
}
return float32(p.value)
}
type cfBoolean bool
func (cfBoolean) typeName() string {
return "boolean"
}
func (p cfBoolean) hash() interface{} {
return bool(p)
}
type cfUID UID
func (cfUID) typeName() string {
return "UID"
}
func (p cfUID) hash() interface{} {
return p
}
type cfData []byte
func (cfData) typeName() string {
return "data"
}
func (p cfData) hash() interface{} {
// Data are uniqued by their checksums.
// Todo: Look at calculating this only once and storing it somewhere;
// crc32 is fairly quick, however.
return crc32.ChecksumIEEE([]byte(p))
}
type cfDate time.Time
func (cfDate) typeName() string {
return "date"
}
func (p cfDate) hash() interface{} {
return time.Time(p)
}

226
vendor/github.com/DHowett/go-plist/text_generator.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
package plist
import (
"encoding/hex"
"io"
"strconv"
"time"
)
type textPlistGenerator struct {
writer io.Writer
format int
quotableTable *characterSet
indent string
depth int
dictKvDelimiter, dictEntryDelimiter, arrayDelimiter []byte
}
var (
textPlistTimeLayout = "2006-01-02 15:04:05 -0700"
padding = "0000"
)
func (p *textPlistGenerator) generateDocument(pval cfValue) {
p.writePlistValue(pval)
}
func (p *textPlistGenerator) plistQuotedString(str string) string {
if str == "" {
return `""`
}
s := ""
quot := false
for _, r := range str {
if r > 0xFF {
quot = true
s += `\U`
us := strconv.FormatInt(int64(r), 16)
s += padding[len(us):]
s += us
} else if r > 0x7F {
quot = true
s += `\`
us := strconv.FormatInt(int64(r), 8)
s += padding[1+len(us):]
s += us
} else {
c := uint8(r)
if p.quotableTable.ContainsByte(c) {
quot = true
}
switch c {
case '\a':
s += `\a`
case '\b':
s += `\b`
case '\v':
s += `\v`
case '\f':
s += `\f`
case '\\':
s += `\\`
case '"':
s += `\"`
case '\t', '\r', '\n':
fallthrough
default:
s += string(c)
}
}
}
if quot {
s = `"` + s + `"`
}
return s
}
func (p *textPlistGenerator) deltaIndent(depthDelta int) {
if depthDelta < 0 {
p.depth--
} else if depthDelta > 0 {
p.depth++
}
}
func (p *textPlistGenerator) writeIndent() {
if len(p.indent) == 0 {
return
}
if len(p.indent) > 0 {
p.writer.Write([]byte("\n"))
for i := 0; i < p.depth; i++ {
io.WriteString(p.writer, p.indent)
}
}
}
func (p *textPlistGenerator) writePlistValue(pval cfValue) {
if pval == nil {
return
}
switch pval := pval.(type) {
case *cfDictionary:
pval.sort()
p.writer.Write([]byte(`{`))
p.deltaIndent(1)
for i, k := range pval.keys {
p.writeIndent()
io.WriteString(p.writer, p.plistQuotedString(k))
p.writer.Write(p.dictKvDelimiter)
p.writePlistValue(pval.values[i])
p.writer.Write(p.dictEntryDelimiter)
}
p.deltaIndent(-1)
p.writeIndent()
p.writer.Write([]byte(`}`))
case *cfArray:
p.writer.Write([]byte(`(`))
p.deltaIndent(1)
for _, v := range pval.values {
p.writeIndent()
p.writePlistValue(v)
p.writer.Write(p.arrayDelimiter)
}
p.deltaIndent(-1)
p.writeIndent()
p.writer.Write([]byte(`)`))
case cfString:
io.WriteString(p.writer, p.plistQuotedString(string(pval)))
case *cfNumber:
if p.format == GNUStepFormat {
p.writer.Write([]byte(`<*I`))
}
if pval.signed {
io.WriteString(p.writer, strconv.FormatInt(int64(pval.value), 10))
} else {
io.WriteString(p.writer, strconv.FormatUint(pval.value, 10))
}
if p.format == GNUStepFormat {
p.writer.Write([]byte(`>`))
}
case *cfReal:
if p.format == GNUStepFormat {
p.writer.Write([]byte(`<*R`))
}
// GNUstep does not differentiate between 32/64-bit floats.
io.WriteString(p.writer, strconv.FormatFloat(pval.value, 'g', -1, 64))
if p.format == GNUStepFormat {
p.writer.Write([]byte(`>`))
}
case cfBoolean:
if p.format == GNUStepFormat {
if pval {
p.writer.Write([]byte(`<*BY>`))
} else {
p.writer.Write([]byte(`<*BN>`))
}
} else {
if pval {
p.writer.Write([]byte(`1`))
} else {
p.writer.Write([]byte(`0`))
}
}
case cfData:
var hexencoded [9]byte
var l int
var asc = 9
hexencoded[8] = ' '
p.writer.Write([]byte(`<`))
b := []byte(pval)
for i := 0; i < len(b); i += 4 {
l = i + 4
if l >= len(b) {
l = len(b)
// We no longer need the space - or the rest of the buffer.
// (we used >= above to get this part without another conditional :P)
asc = (l - i) * 2
}
// Fill the buffer (only up to 8 characters, to preserve the space we implicitly include
// at the end of every encode)
hex.Encode(hexencoded[:8], b[i:l])
io.WriteString(p.writer, string(hexencoded[:asc]))
}
p.writer.Write([]byte(`>`))
case cfDate:
if p.format == GNUStepFormat {
p.writer.Write([]byte(`<*D`))
io.WriteString(p.writer, time.Time(pval).In(time.UTC).Format(textPlistTimeLayout))
p.writer.Write([]byte(`>`))
} else {
io.WriteString(p.writer, p.plistQuotedString(time.Time(pval).In(time.UTC).Format(textPlistTimeLayout)))
}
}
}
func (p *textPlistGenerator) Indent(i string) {
p.indent = i
if i == "" {
p.dictKvDelimiter = []byte(`=`)
} else {
// For pretty-printing
p.dictKvDelimiter = []byte(` = `)
}
}
func newTextPlistGenerator(w io.Writer, format int) *textPlistGenerator {
table := &osQuotable
if format == GNUStepFormat {
table = &gsQuotable
}
return &textPlistGenerator{
writer: mustWriter{w},
format: format,
quotableTable: table,
dictKvDelimiter: []byte(`=`),
arrayDelimiter: []byte(`,`),
dictEntryDelimiter: []byte(`;`),
}
}

515
vendor/github.com/DHowett/go-plist/text_parser.go generated vendored Normal file
View File

@ -0,0 +1,515 @@
package plist
import (
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"runtime"
"strings"
"time"
"unicode/utf16"
"unicode/utf8"
)
type textPlistParser struct {
reader io.Reader
format int
input string
start int
pos int
width int
}
func convertU16(buffer []byte, bo binary.ByteOrder) (string, error) {
if len(buffer)%2 != 0 {
return "", errors.New("truncated utf16")
}
tmp := make([]uint16, len(buffer)/2)
for i := 0; i < len(buffer); i += 2 {
tmp[i/2] = bo.Uint16(buffer[i : i+2])
}
return string(utf16.Decode(tmp)), nil
}
func guessEncodingAndConvert(buffer []byte) (string, error) {
if len(buffer) >= 3 && buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF {
// UTF-8 BOM
return zeroCopy8BitString(buffer, 3, len(buffer)-3), nil
} else if len(buffer) >= 2 {
// UTF-16 guesses
switch {
// stream is big-endian (BOM is FE FF or head is 00 XX)
case (buffer[0] == 0xFE && buffer[1] == 0xFF):
return convertU16(buffer[2:], binary.BigEndian)
case (buffer[0] == 0 && buffer[1] != 0):
return convertU16(buffer, binary.BigEndian)
// stream is little-endian (BOM is FE FF or head is XX 00)
case (buffer[0] == 0xFF && buffer[1] == 0xFE):
return convertU16(buffer[2:], binary.LittleEndian)
case (buffer[0] != 0 && buffer[1] == 0):
return convertU16(buffer, binary.LittleEndian)
}
}
// fallback: assume ASCII (not great!)
return zeroCopy8BitString(buffer, 0, len(buffer)), nil
}
func (p *textPlistParser) parseDocument() (pval cfValue, parseError error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
// Wrap all non-invalid-plist errors.
parseError = plistParseError{"text", r.(error)}
}
}()
buffer, err := ioutil.ReadAll(p.reader)
if err != nil {
panic(err)
}
p.input, err = guessEncodingAndConvert(buffer)
if err != nil {
panic(err)
}
val := p.parsePlistValue()
p.skipWhitespaceAndComments()
if p.peek() != eof {
if _, ok := val.(cfString); !ok {
p.error("garbage after end of document")
}
p.start = 0
p.pos = 0
val = p.parseDictionary(true)
}
pval = val
return
}
const eof rune = -1
func (p *textPlistParser) error(e string, args ...interface{}) {
line := strings.Count(p.input[:p.pos], "\n")
char := p.pos - strings.LastIndex(p.input[:p.pos], "\n") - 1
panic(fmt.Errorf("%s at line %d character %d", fmt.Sprintf(e, args...), line, char))
}
func (p *textPlistParser) next() rune {
if int(p.pos) >= len(p.input) {
p.width = 0
return eof
}
r, w := utf8.DecodeRuneInString(p.input[p.pos:])
p.width = w
p.pos += p.width
return r
}
func (p *textPlistParser) backup() {
p.pos -= p.width
}
func (p *textPlistParser) peek() rune {
r := p.next()
p.backup()
return r
}
func (p *textPlistParser) emit() string {
s := p.input[p.start:p.pos]
p.start = p.pos
return s
}
func (p *textPlistParser) ignore() {
p.start = p.pos
}
func (p *textPlistParser) empty() bool {
return p.start == p.pos
}
func (p *textPlistParser) scanUntil(ch rune) {
if x := strings.IndexRune(p.input[p.pos:], ch); x >= 0 {
p.pos += x
return
}
p.pos = len(p.input)
}
func (p *textPlistParser) scanUntilAny(chs string) {
if x := strings.IndexAny(p.input[p.pos:], chs); x >= 0 {
p.pos += x
return
}
p.pos = len(p.input)
}
func (p *textPlistParser) scanCharactersInSet(ch *characterSet) {
for ch.Contains(p.next()) {
}
p.backup()
}
func (p *textPlistParser) scanCharactersNotInSet(ch *characterSet) {
var r rune
for {
r = p.next()
if r == eof || ch.Contains(r) {
break
}
}
p.backup()
}
func (p *textPlistParser) skipWhitespaceAndComments() {
for {
p.scanCharactersInSet(&whitespace)
if strings.HasPrefix(p.input[p.pos:], "//") {
p.scanCharactersNotInSet(&newlineCharacterSet)
} else if strings.HasPrefix(p.input[p.pos:], "/*") {
if x := strings.Index(p.input[p.pos:], "*/"); x >= 0 {
p.pos += x + 2 // skip the */ as well
continue // consume more whitespace
} else {
p.error("unexpected eof in block comment")
}
} else {
break
}
}
p.ignore()
}
func (p *textPlistParser) parseOctalDigits(max int) uint64 {
var val uint64
for i := 0; i < max; i++ {
r := p.next()
if r >= '0' && r <= '7' {
val <<= 3
val |= uint64((r - '0'))
} else {
p.backup()
break
}
}
return val
}
func (p *textPlistParser) parseHexDigits(max int) uint64 {
var val uint64
for i := 0; i < max; i++ {
r := p.next()
if r >= 'a' && r <= 'f' {
val <<= 4
val |= 10 + uint64((r - 'a'))
} else if r >= 'A' && r <= 'F' {
val <<= 4
val |= 10 + uint64((r - 'A'))
} else if r >= '0' && r <= '9' {
val <<= 4
val |= uint64((r - '0'))
} else {
p.backup()
break
}
}
return val
}
// the \ has already been consumed
func (p *textPlistParser) parseEscape() string {
var s string
switch p.next() {
case 'a':
s = "\a"
case 'b':
s = "\b"
case 'v':
s = "\v"
case 'f':
s = "\f"
case 't':
s = "\t"
case 'r':
s = "\r"
case 'n':
s = "\n"
case '\\':
s = `\`
case '"':
s = `"`
case 'x':
s = string(rune(p.parseHexDigits(2)))
case 'u', 'U':
s = string(rune(p.parseHexDigits(4)))
case '0', '1', '2', '3', '4', '5', '6', '7':
p.backup() // we've already consumed one of the digits
s = string(rune(p.parseOctalDigits(3)))
default:
p.backup() // everything else should be accepted
}
p.ignore() // skip the entire escape sequence
return s
}
// the " has already been consumed
func (p *textPlistParser) parseQuotedString() cfString {
p.ignore() // ignore the "
slowPath := false
s := ""
for {
p.scanUntilAny(`"\`)
switch p.peek() {
case eof:
p.error("unexpected eof in quoted string")
case '"':
section := p.emit()
p.pos++ // skip "
if !slowPath {
return cfString(section)
} else {
s += section
return cfString(s)
}
case '\\':
slowPath = true
s += p.emit()
p.next() // consume \
s += p.parseEscape()
}
}
}
func (p *textPlistParser) parseUnquotedString() cfString {
p.scanCharactersNotInSet(&gsQuotable)
s := p.emit()
if s == "" {
p.error("invalid unquoted string (found an unquoted character that should be quoted?)")
}
return cfString(s)
}
// the { has already been consumed
func (p *textPlistParser) parseDictionary(ignoreEof bool) *cfDictionary {
//p.ignore() // ignore the {
var keypv cfValue
keys := make([]string, 0, 32)
values := make([]cfValue, 0, 32)
outer:
for {
p.skipWhitespaceAndComments()
switch p.next() {
case eof:
if !ignoreEof {
p.error("unexpected eof in dictionary")
}
fallthrough
case '}':
break outer
case '"':
keypv = p.parseQuotedString()
default:
p.backup()
keypv = p.parseUnquotedString()
}
// INVARIANT: key can't be nil; parseQuoted and parseUnquoted
// will panic out before they return nil.
p.skipWhitespaceAndComments()
var val cfValue
n := p.next()
if n == ';' {
val = keypv
} else if n == '=' {
// whitespace is consumed within
val = p.parsePlistValue()
p.skipWhitespaceAndComments()
if p.next() != ';' {
p.error("missing ; in dictionary")
}
} else {
p.error("missing = in dictionary")
}
keys = append(keys, string(keypv.(cfString)))
values = append(values, val)
}
return &cfDictionary{keys: keys, values: values}
}
// the ( has already been consumed
func (p *textPlistParser) parseArray() *cfArray {
//p.ignore() // ignore the (
values := make([]cfValue, 0, 32)
outer:
for {
p.skipWhitespaceAndComments()
switch p.next() {
case eof:
p.error("unexpected eof in array")
case ')':
break outer // done here
case ',':
continue // restart; ,) is valid and we don't want to blow it
default:
p.backup()
}
pval := p.parsePlistValue() // whitespace is consumed within
if str, ok := pval.(cfString); ok && string(str) == "" {
// Empty strings in arrays are apparently skipped?
// TODO: Figure out why this was implemented.
continue
}
values = append(values, pval)
}
return &cfArray{values}
}
// the <* have already been consumed
func (p *textPlistParser) parseGNUStepValue() cfValue {
typ := p.next()
p.ignore()
p.scanUntil('>')
if typ == eof || typ == '>' || p.empty() || p.peek() == eof {
p.error("invalid GNUStep extended value")
}
v := p.emit()
p.next() // consume the >
switch typ {
case 'I':
if v[0] == '-' {
n := mustParseInt(v, 10, 64)
return &cfNumber{signed: true, value: uint64(n)}
} else {
n := mustParseUint(v, 10, 64)
return &cfNumber{signed: false, value: n}
}
case 'R':
n := mustParseFloat(v, 64)
return &cfReal{wide: true, value: n} // TODO(DH) 32/64
case 'B':
b := v[0] == 'Y'
return cfBoolean(b)
case 'D':
t, err := time.Parse(textPlistTimeLayout, v)
if err != nil {
p.error(err.Error())
}
return cfDate(t.In(time.UTC))
}
p.error("invalid GNUStep type " + string(typ))
return nil
}
// The < has already been consumed
func (p *textPlistParser) parseHexData() cfData {
buf := make([]byte, 256)
i := 0
c := 0
for {
r := p.next()
switch r {
case eof:
p.error("unexpected eof in data")
case '>':
if c&1 == 1 {
p.error("uneven number of hex digits in data")
}
p.ignore()
return cfData(buf[:i])
case ' ', '\t', '\n', '\r', '\u2028', '\u2029': // more lax than apple here: skip spaces
continue
}
buf[i] <<= 4
if r >= 'a' && r <= 'f' {
buf[i] |= 10 + byte((r - 'a'))
} else if r >= 'A' && r <= 'F' {
buf[i] |= 10 + byte((r - 'A'))
} else if r >= '0' && r <= '9' {
buf[i] |= byte((r - '0'))
} else {
p.error("unexpected hex digit `%c'", r)
}
c++
if c&1 == 0 {
i++
if i >= len(buf) {
realloc := make([]byte, len(buf)*2)
copy(realloc, buf)
buf = realloc
}
}
}
}
func (p *textPlistParser) parsePlistValue() cfValue {
for {
p.skipWhitespaceAndComments()
switch p.next() {
case eof:
return &cfDictionary{}
case '<':
if p.next() == '*' {
p.format = GNUStepFormat
return p.parseGNUStepValue()
}
p.backup()
return p.parseHexData()
case '"':
return p.parseQuotedString()
case '{':
return p.parseDictionary(false)
case '(':
return p.parseArray()
default:
p.backup()
return p.parseUnquotedString()
}
}
}
func newTextPlistParser(r io.Reader) *textPlistParser {
return &textPlistParser{
reader: r,
format: OpenStepFormat,
}
}

43
vendor/github.com/DHowett/go-plist/text_tables.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
package plist
type characterSet [4]uint64
func (s *characterSet) Contains(ch rune) bool {
return ch >= 0 && ch <= 255 && s.ContainsByte(byte(ch))
}
func (s *characterSet) ContainsByte(ch byte) bool {
return (s[ch/64]&(1<<(ch%64)) > 0)
}
// Bitmap of characters that must be inside a quoted string
// when written to an old-style property list
// Low bits represent lower characters, and each uint64 represents 64 characters.
var gsQuotable = characterSet{
0x78001385ffffffff,
0xa800000138000000,
0xffffffffffffffff,
0xffffffffffffffff,
}
// 7f instead of 3f in the top line: CFOldStylePlist.c says . is valid, but they quote it.
var osQuotable = characterSet{
0xf4007f6fffffffff,
0xf8000001f8000001,
0xffffffffffffffff,
0xffffffffffffffff,
}
var whitespace = characterSet{
0x0000000100003f00,
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
}
var newlineCharacterSet = characterSet{
0x0000000000002400,
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
}

170
vendor/github.com/DHowett/go-plist/typeinfo.go generated vendored Normal file
View File

@ -0,0 +1,170 @@
package plist
import (
"reflect"
"strings"
"sync"
)
// typeInfo holds details for the plist representation of a type.
type typeInfo struct {
fields []fieldInfo
}
// fieldInfo holds details for the plist representation of a single field.
type fieldInfo struct {
idx []int
name string
omitEmpty bool
}
var tinfoMap = make(map[reflect.Type]*typeInfo)
var tinfoLock sync.RWMutex
// getTypeInfo returns the typeInfo structure with details necessary
// for marshalling and unmarshalling typ.
func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
tinfoLock.RLock()
tinfo, ok := tinfoMap[typ]
tinfoLock.RUnlock()
if ok {
return tinfo, nil
}
tinfo = &typeInfo{}
if typ.Kind() == reflect.Struct {
n := typ.NumField()
for i := 0; i < n; i++ {
f := typ.Field(i)
if f.PkgPath != "" || f.Tag.Get("plist") == "-" {
continue // Private field
}
// For embedded structs, embed its fields.
if f.Anonymous {
t := f.Type
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() == reflect.Struct {
inner, err := getTypeInfo(t)
if err != nil {
return nil, err
}
for _, finfo := range inner.fields {
finfo.idx = append([]int{i}, finfo.idx...)
if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
return nil, err
}
}
continue
}
}
finfo, err := structFieldInfo(typ, &f)
if err != nil {
return nil, err
}
// Add the field if it doesn't conflict with other fields.
if err := addFieldInfo(typ, tinfo, finfo); err != nil {
return nil, err
}
}
}
tinfoLock.Lock()
tinfoMap[typ] = tinfo
tinfoLock.Unlock()
return tinfo, nil
}
// structFieldInfo builds and returns a fieldInfo for f.
func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) {
finfo := &fieldInfo{idx: f.Index}
// Split the tag from the xml namespace if necessary.
tag := f.Tag.Get("plist")
// Parse flags.
tokens := strings.Split(tag, ",")
tag = tokens[0]
if len(tokens) > 1 {
tag = tokens[0]
for _, flag := range tokens[1:] {
switch flag {
case "omitempty":
finfo.omitEmpty = true
}
}
}
if tag == "" {
// If the name part of the tag is completely empty,
// use the field name
finfo.name = f.Name
return finfo, nil
}
finfo.name = tag
return finfo, nil
}
// addFieldInfo adds finfo to tinfo.fields if there are no
// conflicts, or if conflicts arise from previous fields that were
// obtained from deeper embedded structures than finfo. In the latter
// case, the conflicting entries are dropped.
// A conflict occurs when the path (parent + name) to a field is
// itself a prefix of another path, or when two paths match exactly.
// It is okay for field paths to share a common, shorter prefix.
func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error {
var conflicts []int
// First, figure all conflicts. Most working code will have none.
for i := range tinfo.fields {
oldf := &tinfo.fields[i]
if newf.name == oldf.name {
conflicts = append(conflicts, i)
}
}
// Without conflicts, add the new field and return.
if conflicts == nil {
tinfo.fields = append(tinfo.fields, *newf)
return nil
}
// If any conflict is shallower, ignore the new field.
// This matches the Go field resolution on embedding.
for _, i := range conflicts {
if len(tinfo.fields[i].idx) < len(newf.idx) {
return nil
}
}
// Otherwise, the new field is shallower, and thus takes precedence,
// so drop the conflicting fields from tinfo and append the new one.
for c := len(conflicts) - 1; c >= 0; c-- {
i := conflicts[c]
copy(tinfo.fields[i:], tinfo.fields[i+1:])
tinfo.fields = tinfo.fields[:len(tinfo.fields)-1]
}
tinfo.fields = append(tinfo.fields, *newf)
return nil
}
// value returns v's field value corresponding to finfo.
// It's equivalent to v.FieldByIndex(finfo.idx), but initializes
// and dereferences pointers as necessary.
func (finfo *fieldInfo) value(v reflect.Value) reflect.Value {
for i, x := range finfo.idx {
if i > 0 {
t := v.Type()
if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
}
}
v = v.Field(x)
}
return v
}

317
vendor/github.com/DHowett/go-plist/unmarshal.go generated vendored Normal file
View File

@ -0,0 +1,317 @@
package plist
import (
"encoding"
"fmt"
"reflect"
"runtime"
"time"
)
type incompatibleDecodeTypeError struct {
dest reflect.Type
src string // type name (from cfValue)
}
func (u *incompatibleDecodeTypeError) Error() string {
return fmt.Sprintf("plist: type mismatch: tried to decode plist type `%v' into value of type `%v'", u.src, u.dest)
}
var (
plistUnmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
uidType = reflect.TypeOf(UID(0))
)
func isEmptyInterface(v reflect.Value) bool {
return v.Kind() == reflect.Interface && v.NumMethod() == 0
}
func (p *Decoder) unmarshalPlistInterface(pval cfValue, unmarshalable Unmarshaler) {
err := unmarshalable.UnmarshalPlist(func(i interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
err = r.(error)
}
}()
p.unmarshal(pval, reflect.ValueOf(i))
return
})
if err != nil {
panic(err)
}
}
func (p *Decoder) unmarshalTextInterface(pval cfString, unmarshalable encoding.TextUnmarshaler) {
err := unmarshalable.UnmarshalText([]byte(pval))
if err != nil {
panic(err)
}
}
func (p *Decoder) unmarshalTime(pval cfDate, val reflect.Value) {
val.Set(reflect.ValueOf(time.Time(pval)))
}
func (p *Decoder) unmarshalLaxString(s string, val reflect.Value) {
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i := mustParseInt(s, 10, 64)
val.SetInt(i)
return
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
i := mustParseUint(s, 10, 64)
val.SetUint(i)
return
case reflect.Float32, reflect.Float64:
f := mustParseFloat(s, 64)
val.SetFloat(f)
return
case reflect.Bool:
b := mustParseBool(s)
val.SetBool(b)
return
case reflect.Struct:
if val.Type() == timeType {
t, err := time.Parse(textPlistTimeLayout, s)
if err != nil {
panic(err)
}
val.Set(reflect.ValueOf(t.In(time.UTC)))
return
}
fallthrough
default:
panic(&incompatibleDecodeTypeError{val.Type(), "string"})
}
}
func (p *Decoder) unmarshal(pval cfValue, val reflect.Value) {
if pval == nil {
return
}
if val.Kind() == reflect.Ptr {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
}
val = val.Elem()
}
if isEmptyInterface(val) {
v := p.valueInterface(pval)
val.Set(reflect.ValueOf(v))
return
}
incompatibleTypeError := &incompatibleDecodeTypeError{val.Type(), pval.typeName()}
// time.Time implements TextMarshaler, but we need to parse it as RFC3339
if date, ok := pval.(cfDate); ok {
if val.Type() == timeType {
p.unmarshalTime(date, val)
return
}
panic(incompatibleTypeError)
}
if receiver, can := implementsInterface(val, plistUnmarshalerType); can {
p.unmarshalPlistInterface(pval, receiver.(Unmarshaler))
return
}
if val.Type() != timeType {
if receiver, can := implementsInterface(val, textUnmarshalerType); can {
if str, ok := pval.(cfString); ok {
p.unmarshalTextInterface(str, receiver.(encoding.TextUnmarshaler))
} else {
panic(incompatibleTypeError)
}
return
}
}
typ := val.Type()
switch pval := pval.(type) {
case cfString:
if val.Kind() == reflect.String {
val.SetString(string(pval))
return
}
if p.lax {
p.unmarshalLaxString(string(pval), val)
return
}
panic(incompatibleTypeError)
case *cfNumber:
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val.SetInt(int64(pval.value))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
val.SetUint(pval.value)
default:
panic(incompatibleTypeError)
}
case *cfReal:
if val.Kind() == reflect.Float32 || val.Kind() == reflect.Float64 {
// TODO: Consider warning on a downcast (storing a 64-bit value in a 32-bit reflect)
val.SetFloat(pval.value)
} else {
panic(incompatibleTypeError)
}
case cfBoolean:
if val.Kind() == reflect.Bool {
val.SetBool(bool(pval))
} else {
panic(incompatibleTypeError)
}
case cfData:
if val.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
val.SetBytes([]byte(pval))
} else {
panic(incompatibleTypeError)
}
case cfUID:
if val.Type() == uidType {
val.SetUint(uint64(pval))
} else {
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val.SetInt(int64(pval))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
val.SetUint(uint64(pval))
default:
panic(incompatibleTypeError)
}
}
case *cfArray:
p.unmarshalArray(pval, val)
case *cfDictionary:
p.unmarshalDictionary(pval, val)
}
}
func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
var n int
if val.Kind() == reflect.Slice {
// Slice of element values.
// Grow slice.
cnt := len(a.values) + val.Len()
if cnt >= val.Cap() {
ncap := 2 * cnt
if ncap < 4 {
ncap = 4
}
new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
reflect.Copy(new, val)
val.Set(new)
}
n = val.Len()
val.SetLen(cnt)
} else if val.Kind() == reflect.Array {
if len(a.values) > val.Cap() {
panic(fmt.Errorf("plist: attempted to unmarshal %d values into an array of size %d", len(a.values), val.Cap()))
}
} else {
panic(&incompatibleDecodeTypeError{val.Type(), a.typeName()})
}
// Recur to read element into slice.
for _, sval := range a.values {
p.unmarshal(sval, val.Index(n))
n++
}
return
}
func (p *Decoder) unmarshalDictionary(dict *cfDictionary, val reflect.Value) {
typ := val.Type()
switch val.Kind() {
case reflect.Struct:
tinfo, err := getTypeInfo(typ)
if err != nil {
panic(err)
}
entries := make(map[string]cfValue, len(dict.keys))
for i, k := range dict.keys {
sval := dict.values[i]
entries[k] = sval
}
for _, finfo := range tinfo.fields {
p.unmarshal(entries[finfo.name], finfo.value(val))
}
case reflect.Map:
if val.IsNil() {
val.Set(reflect.MakeMap(typ))
}
for i, k := range dict.keys {
sval := dict.values[i]
keyv := reflect.ValueOf(k).Convert(typ.Key())
mapElem := reflect.New(typ.Elem()).Elem()
p.unmarshal(sval, mapElem)
val.SetMapIndex(keyv, mapElem)
}
default:
panic(&incompatibleDecodeTypeError{typ, dict.typeName()})
}
}
/* *Interface is modelled after encoding/json */
func (p *Decoder) valueInterface(pval cfValue) interface{} {
switch pval := pval.(type) {
case cfString:
return string(pval)
case *cfNumber:
if pval.signed {
return int64(pval.value)
}
return pval.value
case *cfReal:
if pval.wide {
return pval.value
} else {
return float32(pval.value)
}
case cfBoolean:
return bool(pval)
case *cfArray:
return p.arrayInterface(pval)
case *cfDictionary:
return p.dictionaryInterface(pval)
case cfData:
return []byte(pval)
case cfDate:
return time.Time(pval)
case cfUID:
return UID(pval)
}
return nil
}
func (p *Decoder) arrayInterface(a *cfArray) []interface{} {
out := make([]interface{}, len(a.values))
for i, subv := range a.values {
out[i] = p.valueInterface(subv)
}
return out
}
func (p *Decoder) dictionaryInterface(dict *cfDictionary) map[string]interface{} {
out := make(map[string]interface{})
for i, k := range dict.keys {
subv := dict.values[i]
out[k] = p.valueInterface(subv)
}
return out
}

25
vendor/github.com/DHowett/go-plist/util.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
package plist
import "io"
type countedWriter struct {
io.Writer
nbytes int
}
func (w *countedWriter) Write(p []byte) (int, error) {
n, err := w.Writer.Write(p)
w.nbytes += n
return n, err
}
func (w *countedWriter) BytesWritten() int {
return w.nbytes
}
func unsignedGetBase(s string) (string, int) {
if len(s) > 1 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
return s[2:], 16
}
return s, 10
}

185
vendor/github.com/DHowett/go-plist/xml_generator.go generated vendored Normal file
View File

@ -0,0 +1,185 @@
package plist
import (
"bufio"
"encoding/base64"
"encoding/xml"
"io"
"math"
"strconv"
"time"
)
const (
xmlHEADER string = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
xmlDOCTYPE = `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">` + "\n"
xmlArrayTag = "array"
xmlDataTag = "data"
xmlDateTag = "date"
xmlDictTag = "dict"
xmlFalseTag = "false"
xmlIntegerTag = "integer"
xmlKeyTag = "key"
xmlPlistTag = "plist"
xmlRealTag = "real"
xmlStringTag = "string"
xmlTrueTag = "true"
// magic value used in the XML encoding of UIDs
// (stored as a dictionary mapping CF$UID->integer)
xmlCFUIDMagic = "CF$UID"
)
func formatXMLFloat(f float64) string {
switch {
case math.IsInf(f, 1):
return "inf"
case math.IsInf(f, -1):
return "-inf"
case math.IsNaN(f):
return "nan"
}
return strconv.FormatFloat(f, 'g', -1, 64)
}
type xmlPlistGenerator struct {
*bufio.Writer
indent string
depth int
putNewline bool
}
func (p *xmlPlistGenerator) generateDocument(root cfValue) {
p.WriteString(xmlHEADER)
p.WriteString(xmlDOCTYPE)
p.openTag(`plist version="1.0"`)
p.writePlistValue(root)
p.closeTag(xmlPlistTag)
p.Flush()
}
func (p *xmlPlistGenerator) openTag(n string) {
p.writeIndent(1)
p.WriteByte('<')
p.WriteString(n)
p.WriteByte('>')
}
func (p *xmlPlistGenerator) closeTag(n string) {
p.writeIndent(-1)
p.WriteString("</")
p.WriteString(n)
p.WriteByte('>')
}
func (p *xmlPlistGenerator) element(n string, v string) {
p.writeIndent(0)
if len(v) == 0 {
p.WriteByte('<')
p.WriteString(n)
p.WriteString("/>")
} else {
p.WriteByte('<')
p.WriteString(n)
p.WriteByte('>')
err := xml.EscapeText(p.Writer, []byte(v))
if err != nil {
panic(err)
}
p.WriteString("</")
p.WriteString(n)
p.WriteByte('>')
}
}
func (p *xmlPlistGenerator) writeDictionary(dict *cfDictionary) {
dict.sort()
p.openTag(xmlDictTag)
for i, k := range dict.keys {
p.element(xmlKeyTag, k)
p.writePlistValue(dict.values[i])
}
p.closeTag(xmlDictTag)
}
func (p *xmlPlistGenerator) writeArray(a *cfArray) {
p.openTag(xmlArrayTag)
for _, v := range a.values {
p.writePlistValue(v)
}
p.closeTag(xmlArrayTag)
}
func (p *xmlPlistGenerator) writePlistValue(pval cfValue) {
if pval == nil {
return
}
switch pval := pval.(type) {
case cfString:
p.element(xmlStringTag, string(pval))
case *cfNumber:
if pval.signed {
p.element(xmlIntegerTag, strconv.FormatInt(int64(pval.value), 10))
} else {
p.element(xmlIntegerTag, strconv.FormatUint(pval.value, 10))
}
case *cfReal:
p.element(xmlRealTag, formatXMLFloat(pval.value))
case cfBoolean:
if bool(pval) {
p.element(xmlTrueTag, "")
} else {
p.element(xmlFalseTag, "")
}
case cfData:
p.element(xmlDataTag, base64.StdEncoding.EncodeToString([]byte(pval)))
case cfDate:
p.element(xmlDateTag, time.Time(pval).In(time.UTC).Format(time.RFC3339))
case *cfDictionary:
p.writeDictionary(pval)
case *cfArray:
p.writeArray(pval)
case cfUID:
p.openTag(xmlDictTag)
p.element(xmlKeyTag, xmlCFUIDMagic)
p.element(xmlIntegerTag, strconv.FormatUint(uint64(pval), 10))
p.closeTag(xmlDictTag)
}
}
func (p *xmlPlistGenerator) writeIndent(delta int) {
if len(p.indent) == 0 {
return
}
if delta < 0 {
p.depth--
}
if p.putNewline {
// from encoding/xml/marshal.go; it seems to be intended
// to suppress the first newline.
p.WriteByte('\n')
} else {
p.putNewline = true
}
for i := 0; i < p.depth; i++ {
p.WriteString(p.indent)
}
if delta > 0 {
p.depth++
}
}
func (p *xmlPlistGenerator) Indent(i string) {
p.indent = i
}
func newXMLPlistGenerator(w io.Writer) *xmlPlistGenerator {
return &xmlPlistGenerator{Writer: bufio.NewWriter(w)}
}

216
vendor/github.com/DHowett/go-plist/xml_parser.go generated vendored Normal file
View File

@ -0,0 +1,216 @@
package plist
import (
"encoding/base64"
"encoding/xml"
"errors"
"fmt"
"io"
"runtime"
"strings"
"time"
)
type xmlPlistParser struct {
reader io.Reader
xmlDecoder *xml.Decoder
whitespaceReplacer *strings.Replacer
ntags int
}
func (p *xmlPlistParser) parseDocument() (pval cfValue, parseError error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
if _, ok := r.(invalidPlistError); ok {
parseError = r.(error)
} else {
// Wrap all non-invalid-plist errors.
parseError = plistParseError{"XML", r.(error)}
}
}
}()
for {
if token, err := p.xmlDecoder.Token(); err == nil {
if element, ok := token.(xml.StartElement); ok {
pval = p.parseXMLElement(element)
if p.ntags == 0 {
panic(invalidPlistError{"XML", errors.New("no elements encountered")})
}
return
}
} else {
// The first XML parse turned out to be invalid:
// we do not have an XML property list.
panic(invalidPlistError{"XML", err})
}
}
}
func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) cfValue {
var charData xml.CharData
switch element.Name.Local {
case "plist":
p.ntags++
for {
token, err := p.xmlDecoder.Token()
if err != nil {
panic(err)
}
if el, ok := token.(xml.EndElement); ok && el.Name.Local == "plist" {
break
}
if el, ok := token.(xml.StartElement); ok {
return p.parseXMLElement(el)
}
}
return nil
case "string":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
return cfString(charData)
case "integer":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
s := string(charData)
if len(s) == 0 {
panic(errors.New("invalid empty <integer/>"))
}
if s[0] == '-' {
s, base := unsignedGetBase(s[1:])
n := mustParseInt("-"+s, base, 64)
return &cfNumber{signed: true, value: uint64(n)}
} else {
s, base := unsignedGetBase(s)
n := mustParseUint(s, base, 64)
return &cfNumber{signed: false, value: n}
}
case "real":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
n := mustParseFloat(string(charData), 64)
return &cfReal{wide: true, value: n}
case "true", "false":
p.ntags++
p.xmlDecoder.Skip()
b := element.Name.Local == "true"
return cfBoolean(b)
case "date":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
t, err := time.ParseInLocation(time.RFC3339, string(charData), time.UTC)
if err != nil {
panic(err)
}
return cfDate(t)
case "data":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
str := p.whitespaceReplacer.Replace(string(charData))
l := base64.StdEncoding.DecodedLen(len(str))
bytes := make([]uint8, l)
l, err = base64.StdEncoding.Decode(bytes, []byte(str))
if err != nil {
panic(err)
}
return cfData(bytes[:l])
case "dict":
p.ntags++
var key *string
keys := make([]string, 0, 32)
values := make([]cfValue, 0, 32)
for {
token, err := p.xmlDecoder.Token()
if err != nil {
panic(err)
}
if el, ok := token.(xml.EndElement); ok && el.Name.Local == "dict" {
if key != nil {
panic(errors.New("missing value in dictionary"))
}
break
}
if el, ok := token.(xml.StartElement); ok {
if el.Name.Local == "key" {
var k string
p.xmlDecoder.DecodeElement(&k, &el)
key = &k
} else {
if key == nil {
panic(errors.New("missing key in dictionary"))
}
keys = append(keys, *key)
values = append(values, p.parseXMLElement(el))
key = nil
}
}
}
if len(keys) == 1 && keys[0] == "CF$UID" && len(values) == 1 {
if integer, ok := values[0].(*cfNumber); ok {
return cfUID(integer.value)
}
}
return &cfDictionary{keys: keys, values: values}
case "array":
p.ntags++
values := make([]cfValue, 0, 10)
for {
token, err := p.xmlDecoder.Token()
if err != nil {
panic(err)
}
if el, ok := token.(xml.EndElement); ok && el.Name.Local == "array" {
break
}
if el, ok := token.(xml.StartElement); ok {
values = append(values, p.parseXMLElement(el))
}
}
return &cfArray{values}
}
err := fmt.Errorf("encountered unknown element %s", element.Name.Local)
if p.ntags == 0 {
// If out first XML tag is invalid, it might be an openstep data element, ala <abab> or <0101>
panic(invalidPlistError{"XML", err})
}
panic(err)
}
func newXMLPlistParser(r io.Reader) *xmlPlistParser {
return &xmlPlistParser{r, xml.NewDecoder(r), strings.NewReplacer("\t", "", "\n", "", " ", "", "\r", ""), 0}
}

20
vendor/github.com/DHowett/go-plist/zerocopy.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// +build !appengine
package plist
import (
"reflect"
"unsafe"
)
func zeroCopy8BitString(buf []byte, off int, len int) string {
if len == 0 {
return ""
}
var s string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
hdr.Data = uintptr(unsafe.Pointer(&buf[off]))
hdr.Len = len
return s
}

View File

@ -0,0 +1,7 @@
// +build appengine
package plist
func zeroCopy8BitString(buf []byte, off int, len int) string {
return string(buf[off : off+len])
}

24
vendor/github.com/ProtonMail/go-appdir/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

21
vendor/github.com/ProtonMail/go-appdir/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

52
vendor/github.com/ProtonMail/go-appdir/README.md generated vendored Normal file
View File

@ -0,0 +1,52 @@
# go-appdir
[![GoDoc](https://godoc.org/github.com/ProtonMail/go-appdir?status.svg)](https://godoc.org/github.com/ProtonMail/go-appdir)
Minimalistic Go package to get application directories such as config and cache.
Platform | Windows | [Linux/BSDs](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) | macOS
-------- | ------- | ------------------------------------------------------------------------------------------ | -----
User-specific config | `%APPDATA%` (`C:\Users\%USERNAME%\AppData\Roaming`) | `$XDG_CONFIG_HOME` (`$HOME/.config`) | `$HOME/Library/Application Support`
User-specific cache | `%LOCALAPPDATA%` (`C:\Users\%USERNAME%\AppData\Local`) | `$XDG_CACHE_HOME` (`$HOME/.cache`) | `$HOME/Library/Caches`
User-specific logs | `%LOCALAPPDATA%` (`C:\Users\%USERNAME%\AppData\Local`) | `$XDG_STATE_HOME` (`$HOME/.local/state`) | `$HOME/Library/Logs`
Inspired by [`configdir`](https://github.com/shibukawa/configdir).
## Usage
```go
package main
import (
"os"
"path/filepath"
"github.com/ProtonMail/go-appdir"
)
func main() {
// Get directories for our app
dirs := appdir.New("my-awesome-app")
// Get user-specific config dir
p := dirs.UserConfig()
// Create our app config dir
if err := os.MkdirAll(p, 0755); err != nil {
panic(err)
}
// Now we can use it
f, err := os.Create(filepath.Join(p, "config-file"))
if err != nil {
panic(err)
}
defer f.Close()
f.Write([]byte("<3"))
}
```
## License
MIT

17
vendor/github.com/ProtonMail/go-appdir/appdir.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
// Get application directories such as config and cache.
package appdir
// Dirs requests application directories paths.
type Dirs interface {
// Get the user-specific config directory.
UserConfig() string
// Get the user-specific cache directory.
UserCache() string
// Get the user-specific logs directory.
UserLogs() string
}
// New creates a new App with the provided name.
func New(name string) Dirs {
return &dirs{name: name}
}

View File

@ -0,0 +1,22 @@
package appdir
import (
"os"
"path/filepath"
)
type dirs struct {
name string
}
func (d *dirs) UserConfig() string {
return filepath.Join(os.Getenv("HOME"), "Library", "Application Support", d.name)
}
func (d *dirs) UserCache() string {
return filepath.Join(os.Getenv("HOME"), "Library", "Caches", d.name)
}
func (d *dirs) UserLogs() string {
return filepath.Join(os.Getenv("HOME"), "Library", "Logs", d.name)
}

View File

@ -0,0 +1,22 @@
package appdir
import (
"os"
"path/filepath"
)
type dirs struct {
name string
}
func (d *dirs) UserConfig() string {
return filepath.Join(os.Getenv("APPDATA"), d.name)
}
func (d *dirs) UserCache() string {
return filepath.Join(os.Getenv("LOCALAPPDATA"), d.name)
}
func (d *dirs) UserLogs() string {
return filepath.Join(os.Getenv("LOCALAPPDATA"), d.name)
}

39
vendor/github.com/ProtonMail/go-appdir/appdir_xdg.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
// +build !darwin,!windows
package appdir
import (
"os"
"path/filepath"
)
type dirs struct {
name string
}
func (d *dirs) UserConfig() string {
baseDir := filepath.Join(os.Getenv("HOME"), ".config")
if os.Getenv("XDG_CONFIG_HOME") != "" {
baseDir = os.Getenv("XDG_CONFIG_HOME")
}
return filepath.Join(baseDir, d.name)
}
func (d *dirs) UserCache() string {
baseDir := filepath.Join(os.Getenv("HOME"), ".cache")
if os.Getenv("XDG_CACHE_HOME") != "" {
baseDir = os.Getenv("XDG_CACHE_HOME")
}
return filepath.Join(baseDir, d.name)
}
func (d *dirs) UserLogs() string {
baseDir := filepath.Join(os.Getenv("HOME"), ".local", "state")
if os.Getenv("XDG_STATE_HOME") != "" {
baseDir = os.Getenv("XDG_STATE_HOME")
}
return filepath.Join(baseDir, d.name)
}

32
vendor/github.com/ProtonMail/go-appdir/main.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
// +build ignore
package main
import (
"os"
"path/filepath"
"github.com/ProtonMail/go-appdir"
)
func main() {
// Get directories for our app
dirs := appdir.New("my-awesome-app")
// Get user-specific config dir
p := dirs.UserConfig()
// Create our app config dir
if err := os.MkdirAll(p, 0755); err != nil {
panic(err)
}
// Now we can use it
f, err := os.Create(filepath.Join(p, "config-file"))
if err != nil {
panic(err)
}
defer f.Close()
f.Write([]byte("<3"))
}

20
vendor/github.com/StackExchange/wmi/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Stack Exchange
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

6
vendor/github.com/StackExchange/wmi/README.md generated vendored Normal file
View File

@ -0,0 +1,6 @@
wmi
===
Package wmi provides a WQL interface to Windows WMI.
Note: It interfaces with WMI on the local machine, therefore it only runs on Windows.

260
vendor/github.com/StackExchange/wmi/swbemservices.go generated vendored Normal file
View File

@ -0,0 +1,260 @@
// +build windows
package wmi
import (
"fmt"
"reflect"
"runtime"
"sync"
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
)
// SWbemServices is used to access wmi. See https://msdn.microsoft.com/en-us/library/aa393719(v=vs.85).aspx
type SWbemServices struct {
//TODO: track namespace. Not sure if we can re connect to a different namespace using the same instance
cWMIClient *Client //This could also be an embedded struct, but then we would need to branch on Client vs SWbemServices in the Query method
sWbemLocatorIUnknown *ole.IUnknown
sWbemLocatorIDispatch *ole.IDispatch
queries chan *queryRequest
closeError chan error
lQueryorClose sync.Mutex
}
type queryRequest struct {
query string
dst interface{}
args []interface{}
finished chan error
}
// InitializeSWbemServices will return a new SWbemServices object that can be used to query WMI
func InitializeSWbemServices(c *Client, connectServerArgs ...interface{}) (*SWbemServices, error) {
//fmt.Println("InitializeSWbemServices: Starting")
//TODO: implement connectServerArgs as optional argument for init with connectServer call
s := new(SWbemServices)
s.cWMIClient = c
s.queries = make(chan *queryRequest)
initError := make(chan error)
go s.process(initError)
err, ok := <-initError
if ok {
return nil, err //Send error to caller
}
//fmt.Println("InitializeSWbemServices: Finished")
return s, nil
}
// Close will clear and release all of the SWbemServices resources
func (s *SWbemServices) Close() error {
s.lQueryorClose.Lock()
if s == nil || s.sWbemLocatorIDispatch == nil {
s.lQueryorClose.Unlock()
return fmt.Errorf("SWbemServices is not Initialized")
}
if s.queries == nil {
s.lQueryorClose.Unlock()
return fmt.Errorf("SWbemServices has been closed")
}
//fmt.Println("Close: sending close request")
var result error
ce := make(chan error)
s.closeError = ce //Race condition if multiple callers to close. May need to lock here
close(s.queries) //Tell background to shut things down
s.lQueryorClose.Unlock()
err, ok := <-ce
if ok {
result = err
}
//fmt.Println("Close: finished")
return result
}
func (s *SWbemServices) process(initError chan error) {
//fmt.Println("process: starting background thread initialization")
//All OLE/WMI calls must happen on the same initialized thead, so lock this goroutine
runtime.LockOSThread()
defer runtime.LockOSThread()
err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
if err != nil {
oleCode := err.(*ole.OleError).Code()
if oleCode != ole.S_OK && oleCode != S_FALSE {
initError <- fmt.Errorf("ole.CoInitializeEx error: %v", err)
return
}
}
defer ole.CoUninitialize()
unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
if err != nil {
initError <- fmt.Errorf("CreateObject SWbemLocator error: %v", err)
return
} else if unknown == nil {
initError <- ErrNilCreateObject
return
}
defer unknown.Release()
s.sWbemLocatorIUnknown = unknown
dispatch, err := s.sWbemLocatorIUnknown.QueryInterface(ole.IID_IDispatch)
if err != nil {
initError <- fmt.Errorf("SWbemLocator QueryInterface error: %v", err)
return
}
defer dispatch.Release()
s.sWbemLocatorIDispatch = dispatch
// we can't do the ConnectServer call outside the loop unless we find a way to track and re-init the connectServerArgs
//fmt.Println("process: initialized. closing initError")
close(initError)
//fmt.Println("process: waiting for queries")
for q := range s.queries {
//fmt.Printf("process: new query: len(query)=%d\n", len(q.query))
errQuery := s.queryBackground(q)
//fmt.Println("process: s.queryBackground finished")
if errQuery != nil {
q.finished <- errQuery
}
close(q.finished)
}
//fmt.Println("process: queries channel closed")
s.queries = nil //set channel to nil so we know it is closed
//TODO: I think the Release/Clear calls can panic if things are in a bad state.
//TODO: May need to recover from panics and send error to method caller instead.
close(s.closeError)
}
// Query runs the WQL query using a SWbemServices instance and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool, or a pointer to one of those.
// Array types are not supported.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
func (s *SWbemServices) Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
s.lQueryorClose.Lock()
if s == nil || s.sWbemLocatorIDispatch == nil {
s.lQueryorClose.Unlock()
return fmt.Errorf("SWbemServices is not Initialized")
}
if s.queries == nil {
s.lQueryorClose.Unlock()
return fmt.Errorf("SWbemServices has been closed")
}
//fmt.Println("Query: Sending query request")
qr := queryRequest{
query: query,
dst: dst,
args: connectServerArgs,
finished: make(chan error),
}
s.queries <- &qr
s.lQueryorClose.Unlock()
err, ok := <-qr.finished
if ok {
//fmt.Println("Query: Finished with error")
return err //Send error to caller
}
//fmt.Println("Query: Finished")
return nil
}
func (s *SWbemServices) queryBackground(q *queryRequest) error {
if s == nil || s.sWbemLocatorIDispatch == nil {
return fmt.Errorf("SWbemServices is not Initialized")
}
wmi := s.sWbemLocatorIDispatch //Should just rename in the code, but this will help as we break things apart
//fmt.Println("queryBackground: Starting")
dv := reflect.ValueOf(q.dst)
if dv.Kind() != reflect.Ptr || dv.IsNil() {
return ErrInvalidEntityType
}
dv = dv.Elem()
mat, elemType := checkMultiArg(dv)
if mat == multiArgTypeInvalid {
return ErrInvalidEntityType
}
// service is a SWbemServices
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", q.args...)
if err != nil {
return err
}
service := serviceRaw.ToIDispatch()
defer serviceRaw.Clear()
// result is a SWBemObjectSet
resultRaw, err := oleutil.CallMethod(service, "ExecQuery", q.query)
if err != nil {
return err
}
result := resultRaw.ToIDispatch()
defer resultRaw.Clear()
count, err := oleInt64(result, "Count")
if err != nil {
return err
}
enumProperty, err := result.GetProperty("_NewEnum")
if err != nil {
return err
}
defer enumProperty.Clear()
enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant)
if err != nil {
return err
}
if enum == nil {
return fmt.Errorf("can't get IEnumVARIANT, enum is nil")
}
defer enum.Release()
// Initialize a slice with Count capacity
dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count)))
var errFieldMismatch error
for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) {
if err != nil {
return err
}
err := func() error {
// item is a SWbemObject, but really a Win32_Process
item := itemRaw.ToIDispatch()
defer item.Release()
ev := reflect.New(elemType)
if err = s.cWMIClient.loadEntity(ev.Interface(), item); err != nil {
if _, ok := err.(*ErrFieldMismatch); ok {
// We continue loading entities even in the face of field mismatch errors.
// If we encounter any other error, that other error is returned. Otherwise,
// an ErrFieldMismatch is returned.
errFieldMismatch = err
} else {
return err
}
}
if mat != multiArgTypeStructPtr {
ev = ev.Elem()
}
dv.Set(reflect.Append(dv, ev))
return nil
}()
if err != nil {
return err
}
}
//fmt.Println("queryBackground: Finished")
return errFieldMismatch
}

486
vendor/github.com/StackExchange/wmi/wmi.go generated vendored Normal file
View File

@ -0,0 +1,486 @@
// +build windows
/*
Package wmi provides a WQL interface for WMI on Windows.
Example code to print names of running processes:
type Win32_Process struct {
Name string
}
func main() {
var dst []Win32_Process
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
if err != nil {
log.Fatal(err)
}
for i, v := range dst {
println(i, v.Name)
}
}
*/
package wmi
import (
"bytes"
"errors"
"fmt"
"log"
"os"
"reflect"
"runtime"
"strconv"
"strings"
"sync"
"time"
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
)
var l = log.New(os.Stdout, "", log.LstdFlags)
var (
ErrInvalidEntityType = errors.New("wmi: invalid entity type")
// ErrNilCreateObject is the error returned if CreateObject returns nil even
// if the error was nil.
ErrNilCreateObject = errors.New("wmi: create object returned nil")
lock sync.Mutex
)
// S_FALSE is returned by CoInitializeEx if it was already called on this thread.
const S_FALSE = 0x00000001
// QueryNamespace invokes Query with the given namespace on the local machine.
func QueryNamespace(query string, dst interface{}, namespace string) error {
return Query(query, dst, nil, namespace)
}
// Query runs the WQL query and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool, or a pointer to one of those.
// Array types are not supported.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
//
// Query is a wrapper around DefaultClient.Query.
func Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
if DefaultClient.SWbemServicesClient == nil {
return DefaultClient.Query(query, dst, connectServerArgs...)
}
return DefaultClient.SWbemServicesClient.Query(query, dst, connectServerArgs...)
}
// A Client is an WMI query client.
//
// Its zero value (DefaultClient) is a usable client.
type Client struct {
// NonePtrZero specifies if nil values for fields which aren't pointers
// should be returned as the field types zero value.
//
// Setting this to true allows stucts without pointer fields to be used
// without the risk failure should a nil value returned from WMI.
NonePtrZero bool
// PtrNil specifies if nil values for pointer fields should be returned
// as nil.
//
// Setting this to true will set pointer fields to nil where WMI
// returned nil, otherwise the types zero value will be returned.
PtrNil bool
// AllowMissingFields specifies that struct fields not present in the
// query result should not result in an error.
//
// Setting this to true allows custom queries to be used with full
// struct definitions instead of having to define multiple structs.
AllowMissingFields bool
// SWbemServiceClient is an optional SWbemServices object that can be
// initialized and then reused across multiple queries. If it is null
// then the method will initialize a new temporary client each time.
SWbemServicesClient *SWbemServices
}
// DefaultClient is the default Client and is used by Query, QueryNamespace
var DefaultClient = &Client{}
// Query runs the WQL query and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool, or a pointer to one of those.
// Array types are not supported.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
func (c *Client) Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
dv := reflect.ValueOf(dst)
if dv.Kind() != reflect.Ptr || dv.IsNil() {
return ErrInvalidEntityType
}
dv = dv.Elem()
mat, elemType := checkMultiArg(dv)
if mat == multiArgTypeInvalid {
return ErrInvalidEntityType
}
lock.Lock()
defer lock.Unlock()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
if err != nil {
oleCode := err.(*ole.OleError).Code()
if oleCode != ole.S_OK && oleCode != S_FALSE {
return err
}
}
defer ole.CoUninitialize()
unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
if err != nil {
return err
} else if unknown == nil {
return ErrNilCreateObject
}
defer unknown.Release()
wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
if err != nil {
return err
}
defer wmi.Release()
// service is a SWbemServices
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", connectServerArgs...)
if err != nil {
return err
}
service := serviceRaw.ToIDispatch()
defer serviceRaw.Clear()
// result is a SWBemObjectSet
resultRaw, err := oleutil.CallMethod(service, "ExecQuery", query)
if err != nil {
return err
}
result := resultRaw.ToIDispatch()
defer resultRaw.Clear()
count, err := oleInt64(result, "Count")
if err != nil {
return err
}
enumProperty, err := result.GetProperty("_NewEnum")
if err != nil {
return err
}
defer enumProperty.Clear()
enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant)
if err != nil {
return err
}
if enum == nil {
return fmt.Errorf("can't get IEnumVARIANT, enum is nil")
}
defer enum.Release()
// Initialize a slice with Count capacity
dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count)))
var errFieldMismatch error
for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) {
if err != nil {
return err
}
err := func() error {
// item is a SWbemObject, but really a Win32_Process
item := itemRaw.ToIDispatch()
defer item.Release()
ev := reflect.New(elemType)
if err = c.loadEntity(ev.Interface(), item); err != nil {
if _, ok := err.(*ErrFieldMismatch); ok {
// We continue loading entities even in the face of field mismatch errors.
// If we encounter any other error, that other error is returned. Otherwise,
// an ErrFieldMismatch is returned.
errFieldMismatch = err
} else {
return err
}
}
if mat != multiArgTypeStructPtr {
ev = ev.Elem()
}
dv.Set(reflect.Append(dv, ev))
return nil
}()
if err != nil {
return err
}
}
return errFieldMismatch
}
// ErrFieldMismatch is returned when a field is to be loaded into a different
// type than the one it was stored from, or when a field is missing or
// unexported in the destination struct.
// StructType is the type of the struct pointed to by the destination argument.
type ErrFieldMismatch struct {
StructType reflect.Type
FieldName string
Reason string
}
func (e *ErrFieldMismatch) Error() string {
return fmt.Sprintf("wmi: cannot load field %q into a %q: %s",
e.FieldName, e.StructType, e.Reason)
}
var timeType = reflect.TypeOf(time.Time{})
// loadEntity loads a SWbemObject into a struct pointer.
func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismatch error) {
v := reflect.ValueOf(dst).Elem()
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
of := f
isPtr := f.Kind() == reflect.Ptr
if isPtr {
ptr := reflect.New(f.Type().Elem())
f.Set(ptr)
f = f.Elem()
}
n := v.Type().Field(i).Name
if !f.CanSet() {
return &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: "CanSet() is false",
}
}
prop, err := oleutil.GetProperty(src, n)
if err != nil {
if !c.AllowMissingFields {
errFieldMismatch = &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: "no such struct field",
}
}
continue
}
defer prop.Clear()
switch val := prop.Value().(type) {
case int8, int16, int32, int64, int:
v := reflect.ValueOf(val).Int()
switch f.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
f.SetInt(v)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
f.SetUint(uint64(v))
default:
return &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: "not an integer class",
}
}
case uint8, uint16, uint32, uint64:
v := reflect.ValueOf(val).Uint()
switch f.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
f.SetInt(int64(v))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
f.SetUint(v)
default:
return &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: "not an integer class",
}
}
case string:
switch f.Kind() {
case reflect.String:
f.SetString(val)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
iv, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return err
}
f.SetInt(iv)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
uv, err := strconv.ParseUint(val, 10, 64)
if err != nil {
return err
}
f.SetUint(uv)
case reflect.Struct:
switch f.Type() {
case timeType:
if len(val) == 25 {
mins, err := strconv.Atoi(val[22:])
if err != nil {
return err
}
val = val[:22] + fmt.Sprintf("%02d%02d", mins/60, mins%60)
}
t, err := time.Parse("20060102150405.000000-0700", val)
if err != nil {
return err
}
f.Set(reflect.ValueOf(t))
}
}
case bool:
switch f.Kind() {
case reflect.Bool:
f.SetBool(val)
default:
return &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: "not a bool",
}
}
case float32:
switch f.Kind() {
case reflect.Float32:
f.SetFloat(float64(val))
default:
return &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: "not a Float32",
}
}
default:
if f.Kind() == reflect.Slice {
switch f.Type().Elem().Kind() {
case reflect.String:
safeArray := prop.ToArray()
if safeArray != nil {
arr := safeArray.ToValueArray()
fArr := reflect.MakeSlice(f.Type(), len(arr), len(arr))
for i, v := range arr {
s := fArr.Index(i)
s.SetString(v.(string))
}
f.Set(fArr)
}
case reflect.Uint8:
safeArray := prop.ToArray()
if safeArray != nil {
arr := safeArray.ToValueArray()
fArr := reflect.MakeSlice(f.Type(), len(arr), len(arr))
for i, v := range arr {
s := fArr.Index(i)
s.SetUint(reflect.ValueOf(v).Uint())
}
f.Set(fArr)
}
default:
return &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: fmt.Sprintf("unsupported slice type (%T)", val),
}
}
} else {
typeof := reflect.TypeOf(val)
if typeof == nil && (isPtr || c.NonePtrZero) {
if (isPtr && c.PtrNil) || (!isPtr && c.NonePtrZero) {
of.Set(reflect.Zero(of.Type()))
}
break
}
return &ErrFieldMismatch{
StructType: of.Type(),
FieldName: n,
Reason: fmt.Sprintf("unsupported type (%T)", val),
}
}
}
}
return errFieldMismatch
}
type multiArgType int
const (
multiArgTypeInvalid multiArgType = iota
multiArgTypeStruct
multiArgTypeStructPtr
)
// checkMultiArg checks that v has type []S, []*S for some struct type S.
//
// It returns what category the slice's elements are, and the reflect.Type
// that represents S.
func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) {
if v.Kind() != reflect.Slice {
return multiArgTypeInvalid, nil
}
elemType = v.Type().Elem()
switch elemType.Kind() {
case reflect.Struct:
return multiArgTypeStruct, elemType
case reflect.Ptr:
elemType = elemType.Elem()
if elemType.Kind() == reflect.Struct {
return multiArgTypeStructPtr, elemType
}
}
return multiArgTypeInvalid, nil
}
func oleInt64(item *ole.IDispatch, prop string) (int64, error) {
v, err := oleutil.GetProperty(item, prop)
if err != nil {
return 0, err
}
defer v.Clear()
i := int64(v.Val)
return i, nil
}
// CreateQuery returns a WQL query string that queries all columns of src. where
// is an optional string that is appended to the query, to be used with WHERE
// clauses. In such a case, the "WHERE" string should appear at the beginning.
func CreateQuery(src interface{}, where string) string {
var b bytes.Buffer
b.WriteString("SELECT ")
s := reflect.Indirect(reflect.ValueOf(src))
t := s.Type()
if s.Kind() == reflect.Slice {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return ""
}
var fields []string
for i := 0; i < t.NumField(); i++ {
fields = append(fields, t.Field(i).Name)
}
b.WriteString(strings.Join(fields, ", "))
b.WriteString(" FROM ")
b.WriteString(t.Name())
b.WriteString(" " + where)
return b.String()
}

661
vendor/github.com/cjbassi/drawille-go/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.

24
vendor/github.com/cjbassi/drawille-go/README.md generated vendored Normal file
View File

@ -0,0 +1,24 @@
GO-DRAWILLE
===========
Drawing in the terminal with Unicode Braille characters.
A [go](https://golang.org) port of [asciimoo's](https://github.com/asciimoo) [drawille](https://github.com/asciimoo/drawille)
### LICENSE
```
drawille-go is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
drawille-go is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with drawille-go. If not, see < http://www.gnu.org/licenses/ >.
(C) 2014 by Adam Tauber, <asciimoo@gmail.com>
(C) 2014 by Jacob Hughes, <exrook.j@gmail.com>
```

275
vendor/github.com/cjbassi/drawille-go/drawille.go generated vendored Normal file
View File

@ -0,0 +1,275 @@
package drawille
//import "code.google.com/p/goncurses"
import "math"
var pixel_map = [4][2]int{
{0x1, 0x8},
{0x2, 0x10},
{0x4, 0x20},
{0x40, 0x80}}
// Braille chars start at 0x2800
var braille_char_offset = 0x2800
func getPixel(y, x int) int {
var cy, cx int
if y >= 0 {
cy = y % 4
} else {
cy = 3 + ((y + 1) % 4)
}
if x >= 0 {
cx = x % 2
} else {
cx = 1 + ((x + 1) % 2)
}
return pixel_map[cy][cx]
}
type Canvas struct {
LineEnding string
chars map[int]map[int]int
}
// Make a new canvas
func NewCanvas() Canvas {
c := Canvas{LineEnding: "\n"}
c.Clear()
return c
}
func (c Canvas) MaxY() int {
max := 0
for k, _ := range c.chars {
if k > max {
max = k
}
}
return max * 4
}
func (c Canvas) MinY() int {
min := 0
for k, _ := range c.chars {
if k < min {
min = k
}
}
return min * 4
}
func (c Canvas) MaxX() int {
max := 0
for _, v := range c.chars {
for k, _ := range v {
if k > max {
max = k
}
}
}
return max * 2
}
func (c Canvas) MinX() int {
min := 0
for _, v := range c.chars {
for k, _ := range v {
if k < min {
min = k
}
}
}
return min * 2
}
// Clear all pixels
func (c *Canvas) Clear() {
c.chars = make(map[int]map[int]int)
}
// Convert x,y to cols, rows
func (c Canvas) get_pos(x, y int) (int, int) {
return (x / 2), (y / 4)
}
// Set a pixel of c
func (c *Canvas) Set(x, y int) {
px, py := c.get_pos(x, y)
if m := c.chars[py]; m == nil {
c.chars[py] = make(map[int]int)
}
val := c.chars[py][px]
mapv := getPixel(y, x)
c.chars[py][px] = val | mapv
}
// Unset a pixel of c
func (c *Canvas) UnSet(x, y int) {
px, py := c.get_pos(x, y)
x, y = int(math.Abs(float64(x))), int(math.Abs(float64(y)))
if m := c.chars[py]; m == nil {
c.chars[py] = make(map[int]int)
}
c.chars[py][px] = c.chars[py][px] &^ getPixel(y, x)
}
// Toggle a point
func (c *Canvas) Toggle(x, y int) {
px, py := c.get_pos(x, y)
if (c.chars[py][px] & getPixel(y, x)) != 0 {
c.UnSet(x, y)
} else {
c.Set(x, y)
}
}
// Set text to the given coordinates
func (c *Canvas) SetText(x, y int, text string) {
x, y = x/2, y/4
if m := c.chars[y]; m == nil {
c.chars[y] = make(map[int]int)
}
for i, char := range text {
c.chars[y][x+i] = int(char) - braille_char_offset
}
}
// Get pixel at the given coordinates
func (c Canvas) Get(x, y int) bool {
dot_index := pixel_map[y%4][x%2]
x, y = x/2, y/4
char := c.chars[y][x]
return (char & dot_index) != 0
}
// Get character at the given screen coordinates
func (c Canvas) GetScreenCharacter(x, y int) rune {
return rune(c.chars[y][x] + braille_char_offset)
}
// Get character for the given pixel
func (c Canvas) GetCharacter(x, y int) rune {
return c.GetScreenCharacter(x/4, y/4)
}
// Retrieve the rows from a given view
func (c Canvas) Rows(minX, minY, maxX, maxY int) []string {
minrow, maxrow := minY/4, (maxY)/4
mincol, maxcol := minX/2, (maxX)/2
ret := make([]string, 0)
for rownum := minrow; rownum < (maxrow + 1); rownum = rownum + 1 {
row := ""
for x := mincol; x < (maxcol + 1); x = x + 1 {
char := c.chars[rownum][x]
row += string(rune(char + braille_char_offset))
}
ret = append(ret, row)
}
return ret
}
// Retrieve a string representation of the frame at the given parameters
func (c Canvas) Frame(minX, minY, maxX, maxY int) string {
var ret string
for _, row := range c.Rows(minX, minY, maxX, maxY) {
ret += row
ret += c.LineEnding
}
return ret
}
func (c Canvas) String() string {
return c.Frame(c.MinX(), c.MinY(), c.MaxX(), c.MaxY())
}
type Point struct {
X, Y int
}
// Line returns []Point where each Point is a dot in the line
func Line(x1, y1, x2, y2 int) []Point {
xdiff := abs(x1 - x2)
ydiff := abs(y2 - y1)
var xdir, ydir int
if x1 <= x2 {
xdir = 1
} else {
xdir = -1
}
if y1 <= y2 {
ydir = 1
} else {
ydir = -1
}
r := max(xdiff, ydiff)
points := make([]Point, r+1)
for i := 0; i <= r; i++ {
x, y := x1, y1
if ydiff != 0 {
y += (i * ydiff) / (r * ydir)
}
if xdiff != 0 {
x += (i * xdiff) / (r * xdir)
}
points[i] = Point{x, y}
}
return points
}
// DrawLine draws a line onto the Canvas
func (c *Canvas) DrawLine(x1, y1, x2, y2 int) {
for _, p := range Line(x1, y1, x2, y2) {
c.Set(p.X, p.Y)
}
}
func (c *Canvas) DrawPolygon(center_x, center_y, sides, radius float64) {
degree := 360 / sides
for n := 0; n < int(sides); n = n + 1 {
a := float64(n) * degree
b := float64(n+1) * degree
x1 := int(center_x + (math.Cos(radians(a)) * (radius/2 + 1)))
y1 := int(center_y + (math.Sin(radians(a)) * (radius/2 + 1)))
x2 := int(center_x + (math.Cos(radians(b)) * (radius/2 + 1)))
y2 := int(center_y + (math.Sin(radians(b)) * (radius/2 + 1)))
c.DrawLine(x1, y1, x2, y2)
}
}
func radians(d float64) float64 {
return d * (math.Pi / 180)
}
func round(x float64) int {
return int(x + 0.5)
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
func abs(x int) int {
if x < 0 {
return x * -1
}
return x
}

2
vendor/github.com/distatus/battery/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
cmd/battery/battery*
coverage.html

12
vendor/github.com/distatus/battery/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,12 @@
language: go
go:
- 1.3
- 1.4
- 1.5
- 1.6
- tip
matrix:
allow_failures:
- go: tip

20
vendor/github.com/distatus/battery/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,20 @@
battery
Copyright (C) 2016 Karol 'Kenji Takahashi' Woźniak
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

71
vendor/github.com/distatus/battery/README.md generated vendored Normal file
View File

@ -0,0 +1,71 @@
battery [![Build Status](https://travis-ci.org/distatus/battery.svg?branch=master)](https://travis-ci.org/distatus/battery) [![Go Report Card](https://goreportcard.com/badge/github.com/distatus/battery)](https://goreportcard.com/report/github.com/distatus/battery) [![GoDoc](https://godoc.org/github.com/distatus/battery?status.svg)](https://godoc.org/github.com/distatus/battery)
=======
Cross-platform, normalized battery information library.
Gives access to a system independent, typed battery state, capacity, charge and voltage values recalculated as necessary to be returned in mW, mWh or V units.
Currently supported systems:
* Linux 2.6.39+
* OS X 10.10+
* Windows XP+
* FreeBSD
* DragonFlyBSD
* NetBSD
* OpenBSD
* Solaris
Installation
------------
```bash
$ go get -u github.com/distatus/battery
```
Code Example
------------
```go
import (
"fmt"
"github.com/distatus/battery"
)
func main() {
batteries, err := battery.GetAll()
if err != nil {
fmt.Println("Could not get battery info!")
return
}
for i, battery := range batteries {
fmt.Printf("Bat%d: ", i)
fmt.Printf("state: %f, ", battery.State)
fmt.Printf("current capacity: %f mWh, ", battery.Current)
fmt.Printf("last full capacity: %f mWh, ", battery.Full)
fmt.Printf("design capacity: %f mWh, ", battery.Design)
fmt.Printf("charge rate: %f mW, ", battery.ChargeRate)
fmt.Printf("voltage: %f V, ", battery.Voltage)
fmt.Printf("design voltage: %f V\n", battery.DesignVoltage)
}
}
```
CLI
---
There is also a little utility which - more or less - mimicks the GNU/Linux `acpi -b` command.
*Installation*
```bash
$ go get -u github.com/distatus/battery/cmd/battery
```
*Usage*
```bash
$ battery
BAT0: Full, 95.61% [Voltage: 12.15V (design: 12.15V)]
```

156
vendor/github.com/distatus/battery/battery.go generated vendored Normal file
View File

@ -0,0 +1,156 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Package battery provides cross-platform, normalized battery information.
//
// Gives access to a system independent, typed battery state, capacity, charge and voltage values recalculated as necessary to be returned in mW, mWh or V units.
//
// Currently supported systems:
// Linux 2.6.39+
// OS X 10.10+
// Windows XP+
// FreeBSD
// DragonFlyBSD
// NetBSD
// OpenBSD
// Solaris
package battery
import (
"fmt"
"strings"
)
// State type enumerates possible battery states.
type State int
// Possible state values.
// Unknown can mean either controller returned unknown, or
// not able to retrieve state due to some error.
const (
Unknown State = iota
Empty
Full
Charging
Discharging
)
var states = [...]string{
Unknown: "Unknown",
Empty: "Empty",
Full: "Full",
Charging: "Charging",
Discharging: "Discharging",
}
func (s State) String() string {
return states[s]
}
func newState(name string) (State, error) {
for i, state := range states {
if strings.EqualFold(name, state) {
return State(i), nil
}
}
return Unknown, fmt.Errorf("Invalid state `%s`", name)
}
// Battery type represents a single battery entry information.
type Battery struct {
// Current battery state.
State State
// Current (momentary) capacity (in mWh).
Current float64
// Last known full capacity (in mWh).
Full float64
// Reported design capacity (in mWh).
Design float64
// Current (momentary) charge rate (in mW).
// It is always non-negative, consult .State field to check
// whether it means charging or discharging.
ChargeRate float64
// Current voltage (in V).
Voltage float64
// Design voltage (in V).
// Some systems (e.g. macOS) do not provide a separate
// value for this. In such cases, or if getting this fails,
// but getting `Voltage` succeeds, this field will have
// the same value as `Voltage`, for convenience.
DesignVoltage float64
}
func (b *Battery) String() string {
return fmt.Sprintf("%+v", *b)
}
func get(sg func(idx int) (*Battery, error), idx int) (*Battery, error) {
b, err := sg(idx)
return b, wrapError(err)
}
// Get returns battery information for given index.
//
// Note that index taken here is normalized, such that GetAll()[idx] == Get(idx).
// It does not necessarily represent the "name" or "position" a battery was given
// by the underlying system.
//
// If error != nil, it will be either ErrFatal or ErrPartial.
func Get(idx int) (*Battery, error) {
return get(systemGet, idx)
}
func getAll(sg func() ([]*Battery, error)) ([]*Battery, error) {
bs, err := sg()
if errors, ok := err.(Errors); ok {
nils := 0
partials := 0
for i, err := range errors {
err = wrapError(err)
if err == nil {
nils++
}
if _, ok := err.(ErrPartial); ok {
partials++
}
errors[i] = err
}
if nils == len(errors) {
return bs, nil
}
if nils > 0 || partials > 0 {
return bs, errors
}
return nil, ErrFatal{ErrAllNotNil}
}
if err != nil {
return bs, ErrFatal{err}
}
return bs, nil
}
// GetAll returns information about all batteries in the system.
//
// If error != nil, it will be either ErrFatal or Errors.
// If error is of type Errors, it is guaranteed that length of both returned slices is the same and that i-th error coresponds with i-th battery structure.
func GetAll() ([]*Battery, error) {
return getAll(systemGetAll)
}

108
vendor/github.com/distatus/battery/battery_darwin.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package battery
import (
"math"
"os/exec"
plist "github.com/DHowett/go-plist"
)
type battery struct {
Voltage int
CurrentCapacity int
MaxCapacity int
DesignCapacity int
Amperage int64
FullyCharged bool
IsCharging bool
ExternalConnected bool
}
func readBatteries() ([]*battery, error) {
out, err := exec.Command("ioreg", "-n", "AppleSmartBattery", "-r", "-a").Output()
if err != nil {
return nil, err
}
if len(out) == 0 {
// No batteries.
return nil, nil
}
var data []*battery
if _, err = plist.Unmarshal(out, &data); err != nil {
return nil, err
}
return data, nil
}
func convertBattery(battery *battery) *Battery {
volts := float64(battery.Voltage) / 1000
b := &Battery{
Current: float64(battery.CurrentCapacity) * volts,
Full: float64(battery.MaxCapacity) * volts,
Design: float64(battery.DesignCapacity) * volts,
ChargeRate: math.Abs(float64(battery.Amperage)) * volts,
Voltage: volts,
DesignVoltage: volts,
}
switch {
case !battery.ExternalConnected:
b.State, _ = newState("Discharging")
case battery.IsCharging:
b.State, _ = newState("Charging")
case battery.CurrentCapacity == 0:
b.State, _ = newState("Empty")
case battery.FullyCharged:
b.State, _ = newState("Full")
default:
b.State, _ = newState("Unknown")
}
return b
}
func systemGet(idx int) (*Battery, error) {
batteries, err := readBatteries()
if err != nil {
return nil, err
}
if idx >= len(batteries) {
return nil, ErrNotFound
}
return convertBattery(batteries[idx]), nil
}
func systemGetAll() ([]*Battery, error) {
_batteries, err := readBatteries()
if err != nil {
return nil, err
}
batteries := make([]*Battery, len(_batteries))
for i, battery := range _batteries {
batteries[i] = convertBattery(battery)
}
return batteries, nil
}

View File

@ -0,0 +1,148 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// +build freebsd dragonfly
package battery
import (
"errors"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
func readUint32(bytes []byte) uint32 {
var ret uint32
for i, b := range bytes {
ret |= uint32(b) << uint(i*8)
}
return ret
}
func uint32ToFloat64(num uint32) (float64, error) {
if num == 0xffffffff {
return 0, errors.New("Unknown value received")
}
return float64(num), nil
}
func ioctl_(fd int, nr int64, retptr *[164]byte) error {
return ioctl(fd, nr, 'B', unsafe.Sizeof(*retptr), unsafe.Pointer(retptr))
}
func systemGet(idx int) (*Battery, error) {
fd, err := unix.Open("/dev/acpi", unix.O_RDONLY, 0777)
if err != nil {
return nil, err
}
defer unix.Close(fd)
b := &Battery{}
e := ErrPartial{}
// No unions in Go, so lets "emulate" union with byte array ;-].
var retptr [164]byte
unit := (*int)(unsafe.Pointer(&retptr[0]))
*unit = idx
err = ioctl_(fd, 0x10, &retptr) // ACPIIO_BATT_GET_BIF
if err != nil {
return nil, err
}
mw := readUint32(retptr[0:4]) == 0 // acpi_bif.units
b.Design, e.Design = uint32ToFloat64(readUint32(retptr[4:8])) // acpi_bif.dcap
b.Full, e.Full = uint32ToFloat64(readUint32(retptr[8:12])) // acpi_bif.lfcap
b.DesignVoltage, e.DesignVoltage = uint32ToFloat64(readUint32(retptr[16:20])) // acpi_bif.dvol
b.DesignVoltage /= 1000
*unit = idx
err = ioctl_(fd, 0x11, &retptr) // APCIIO_BATT_GET_BST
if err == nil {
switch readUint32(retptr[0:4]) { // acpi_bst.state
case 0x0000:
b.State = Full
case 0x0001:
b.State = Discharging
case 0x0002:
b.State = Charging
case 0x0004:
b.State = Empty
default:
b.State = Unknown
}
b.ChargeRate, e.ChargeRate = uint32ToFloat64(readUint32(retptr[4:8])) // acpi_bst.rate
b.Current, e.Current = uint32ToFloat64(readUint32(retptr[8:12])) // acpi_bst.cap
b.Voltage, e.Voltage = uint32ToFloat64(readUint32(retptr[12:16])) // acpi_bst.volt
b.Voltage /= 1000
} else {
e.State = err
e.ChargeRate = err
e.Current = err
e.Voltage = err
}
if e.DesignVoltage != nil && e.Voltage == nil {
b.DesignVoltage, e.DesignVoltage = b.Voltage, nil
}
if !mw {
if e.DesignVoltage == nil {
b.Design *= b.DesignVoltage
} else {
e.Design = e.DesignVoltage
}
if e.Voltage == nil {
b.Full *= b.Voltage
b.ChargeRate *= b.Voltage
b.Current *= b.Voltage
} else {
e.Full = e.Voltage
e.ChargeRate = e.Voltage
e.Current = e.Voltage
}
}
return b, e
}
// There is no way to iterate over available batteries.
// Therefore we assume here that if we were not able to retrieve
// anything, it means we're done.
func systemGetAll() ([]*Battery, error) {
var batteries []*Battery
var errors Errors
for i := 0; ; i++ {
b, err := systemGet(i)
if perr, ok := err.(ErrPartial); ok && perr.noNil() {
break
}
if errno, ok := err.(syscall.Errno); ok && errno == 6 {
break
}
batteries = append(batteries, b)
errors = append(errors, err)
}
return batteries, errors
}

147
vendor/github.com/distatus/battery/battery_linux.go generated vendored Normal file
View File

@ -0,0 +1,147 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package battery
import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
)
const sysfs = "/sys/class/power_supply"
func readFloat(path, filename string) (float64, error) {
str, err := ioutil.ReadFile(filepath.Join(path, filename))
if err != nil {
return 0, err
}
num, err := strconv.ParseFloat(string(str[:len(str)-1]), 64)
if err != nil {
return 0, err
}
return num / 1000, nil // Convert micro->milli
}
func readAmp(path, filename string, volts float64) (float64, error) {
val, err := readFloat(path, filename)
if err != nil {
return 0, err
}
return val * volts, nil
}
func isBattery(path string) bool {
t, err := ioutil.ReadFile(filepath.Join(path, "type"))
return err == nil && string(t) == "Battery\n"
}
func getBatteryFiles() ([]string, error) {
files, err := ioutil.ReadDir(sysfs)
if err != nil {
return nil, err
}
var bFiles []string
for _, file := range files {
path := filepath.Join(sysfs, file.Name())
if isBattery(path) {
bFiles = append(bFiles, path)
}
}
return bFiles, nil
}
func getByPath(path string) (*Battery, error) {
b := &Battery{}
e := ErrPartial{}
b.Current, e.Current = readFloat(path, "energy_now")
b.Voltage, e.Voltage = readFloat(path, "voltage_now")
b.Voltage /= 1000
b.DesignVoltage, e.DesignVoltage = readFloat(path, "voltage_max_design")
if e.DesignVoltage != nil {
b.DesignVoltage, e.DesignVoltage = readFloat(path, "voltage_min_design")
}
if e.DesignVoltage != nil && e.Voltage == nil {
b.DesignVoltage, e.DesignVoltage = b.Voltage, nil
}
b.DesignVoltage /= 1000
if os.IsNotExist(e.Current) {
if e.DesignVoltage == nil {
b.Design, e.Design = readAmp(path, "charge_full_design", b.DesignVoltage)
} else {
e.Design = e.DesignVoltage
}
if e.Voltage == nil {
b.Current, e.Current = readAmp(path, "charge_now", b.Voltage)
b.Full, e.Full = readAmp(path, "charge_full", b.Voltage)
b.ChargeRate, e.ChargeRate = readAmp(path, "current_now", b.Voltage)
} else {
e.Current = e.Voltage
e.Full = e.Voltage
e.ChargeRate = e.Voltage
}
} else {
b.Full, e.Full = readFloat(path, "energy_full")
b.Design, e.Design = readFloat(path, "energy_full_design")
b.ChargeRate, e.ChargeRate = readFloat(path, "power_now")
}
state, err := ioutil.ReadFile(filepath.Join(path, "status"))
if err == nil {
b.State, e.State = newState(string(state[:len(state)-1]))
} else {
e.State = err
}
return b, e
}
func systemGet(idx int) (*Battery, error) {
bFiles, err := getBatteryFiles()
if err != nil {
return nil, err
}
if idx >= len(bFiles) {
return nil, ErrNotFound
}
return getByPath(bFiles[idx])
}
func systemGetAll() ([]*Battery, error) {
bFiles, err := getBatteryFiles()
if err != nil {
return nil, err
}
batteries := make([]*Battery, len(bFiles))
errors := make(Errors, len(bFiles))
for i, bFile := range bFiles {
battery, err := getByPath(bFile)
batteries[i] = battery
errors[i] = err
}
return batteries, errors
}

220
vendor/github.com/distatus/battery/battery_netbsd.go generated vendored Normal file
View File

@ -0,0 +1,220 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package battery
import (
"errors"
"math"
"sort"
"strings"
"unsafe"
plist "github.com/DHowett/go-plist"
"golang.org/x/sys/unix"
)
type plistref struct {
pref_plist unsafe.Pointer
pref_len uint64
}
type values struct {
Description string `plist:"description"`
CurValue int `plist:"cur-value"`
MaxValue int `plist:"max-value"`
State string `plist:"state"`
Type string `plist:"type"`
}
type prop []values
type props map[string]prop
func readBytes(ptr unsafe.Pointer, length uint64) []byte {
buf := make([]byte, length-1)
var i uint64
for ; i < length-1; i++ {
buf[i] = *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(i)))
}
return buf
}
func readProps() (props, error) {
fd, err := unix.Open("/dev/sysmon", unix.O_RDONLY, 0777)
if err != nil {
return nil, err
}
defer unix.Close(fd)
var retptr plistref
if err = ioctl(fd, 0, 'E', unsafe.Sizeof(retptr), unsafe.Pointer(&retptr)); err != nil {
return nil, err
}
bytes := readBytes(retptr.pref_plist, retptr.pref_len)
var props props
if _, err = plist.Unmarshal(bytes, &props); err != nil {
return nil, err
}
return props, nil
}
func handleValue(val values, div float64, res *float64, amps *[]string) error {
if val.State == "invalid" || val.State == "unknown" {
return errors.New("Unknown value received")
}
*res = float64(val.CurValue) / div
if amps != nil && strings.HasPrefix(val.Type, "Amp") {
*amps = append(*amps, val.Description)
}
return nil
}
func deriveState(cr1, cr2 error, current float64, max int) (State, error) {
if cr1 == nil && cr2 != nil {
return Charging, nil
}
if cr1 != nil && cr2 == nil {
return Discharging, nil
}
if cr1 != nil && cr2 != nil && current == float64(max)/1000 {
return Full, nil
}
return Unknown, errors.New("Contradicting values received")
}
func handleVoltage(amps []string, b *Battery, e *ErrPartial) {
if e.DesignVoltage != nil && e.Voltage == nil {
b.DesignVoltage, e.DesignVoltage = b.Voltage, nil
}
for _, val := range amps {
switch val {
case "design cap":
if e.DesignVoltage == nil {
b.Design *= b.DesignVoltage
} else {
e.Design = e.DesignVoltage
}
case "last full cap":
if e.Voltage == nil {
b.Full *= b.Voltage
} else {
e.Full = e.Voltage
}
case "charge":
if e.Voltage == nil {
b.Current *= b.Voltage
} else {
e.Current = e.Voltage
}
case "charge rate", "discharge rate":
if e.Voltage == nil {
b.ChargeRate *= b.Voltage
} else {
e.ChargeRate = e.Voltage
}
}
}
}
func sortFilterProps(props props) []string {
var keys []string
for key := range props {
if key[:7] != "acpibat" {
continue
}
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
func convertBattery(prop prop) (*Battery, error) {
b := &Battery{}
e := ErrPartial{}
amps := []string{}
var cr1, cr2 error
var maxCharge int
for _, val := range prop {
switch val.Description {
case "voltage":
e.Voltage = handleValue(val, 1000000, &b.Voltage, nil)
case "design voltage":
e.DesignVoltage = handleValue(val, 1000000, &b.DesignVoltage, nil)
case "design cap":
e.Design = handleValue(val, 1000, &b.Design, &amps)
case "last full cap":
e.Full = handleValue(val, 1000, &b.Full, &amps)
case "charge":
e.Current = handleValue(val, 1000, &b.Current, &amps)
maxCharge = val.MaxValue
case "charge rate":
cr1 = handleValue(val, 1000, &b.ChargeRate, &amps)
case "discharge rate":
cr2 = handleValue(val, 1000, &b.ChargeRate, &amps)
b.ChargeRate = math.Abs(b.ChargeRate)
}
}
b.State, e.State = deriveState(cr1, cr2, b.Current, maxCharge)
handleVoltage(amps, b, &e)
return b, e
}
func systemGet(idx int) (*Battery, error) {
props, err := readProps()
if err != nil {
return nil, err
}
keys := sortFilterProps(props)
if idx >= len(keys) {
return nil, ErrNotFound
}
return convertBattery(props[keys[idx]])
}
func systemGetAll() ([]*Battery, error) {
props, err := readProps()
if err != nil {
return nil, err
}
keys := sortFilterProps(props)
batteries := make([]*Battery, len(keys))
errors := make(Errors, len(keys))
for i, key := range keys {
batteries[i], errors[i] = convertBattery(props[key])
}
return batteries, errors
}

279
vendor/github.com/distatus/battery/battery_openbsd.go generated vendored Normal file
View File

@ -0,0 +1,279 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package battery
import (
"bytes"
"fmt"
"strings"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
var errValueNotFound = fmt.Errorf("Value not found")
var sensorW = [4]int32{
2, // SENSOR_VOLTS_DC (uV)
5, // SENSOR_WATTS (uW)
7, // SENSOR_WATTHOUR (uWh)
10, // SENSOR_INTEGER
}
const (
sensorA = 6 // SENSOR_AMPS (uA)
sensorAH = 8 // SENSOR_AMPHOUR (uAh)
)
type sensordev struct {
num int32
xname [16]byte
maxnumt [21]int32
sensors_count int32
}
type sensorStatus int32
const (
unspecified sensorStatus = iota
ok
warning
critical
unknown
)
type sensor struct {
desc [32]byte
tv [16]byte // struct timeval
value int64
typ [4]byte // enum sensor_type
status sensorStatus
numt int32
flags int32
}
type interValue struct {
v *float64
s *State
e *error
}
func sysctl(mib []int32, out unsafe.Pointer, n uintptr) syscall.Errno {
_, _, e := unix.Syscall6(
unix.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(len(mib)),
uintptr(out),
uintptr(unsafe.Pointer(&n)),
uintptr(unsafe.Pointer(nil)),
0,
)
return e
}
func readValue(s sensor, div float64) (float64, error) {
if s.status == unknown {
return 0, fmt.Errorf("Unknown value received")
}
return float64(s.value) / div, nil
}
func readValues(mib []int32, c int32, values map[string]*interValue) {
var s sensor
var i int32
for i = 0; i < c; i++ {
mib[4] = i
if err := sysctl(mib, unsafe.Pointer(&s), unsafe.Sizeof(s)); err != 0 {
for _, value := range values {
if *value.e == errValueNotFound {
*value.e = err
}
}
}
desc := string(s.desc[:bytes.IndexByte(s.desc[:], 0)])
isState := strings.HasPrefix(desc, "battery ")
var value *interValue
var ok bool
if isState {
value, ok = values["state"]
} else {
value, ok = values[desc]
}
if !ok {
continue
}
if isState {
//TODO:battery idle(?)
if desc == "battery critical" {
*value.s, *value.e = Empty, nil
} else {
*value.s, *value.e = newState(desc[8:])
}
continue
}
if strings.HasSuffix(desc, "voltage") {
*value.v, *value.e = readValue(s, 1000000)
} else {
*value.v, *value.e = readValue(s, 1000)
}
}
}
func sensordevIter(cb func(sd sensordev, i int, err error) bool) {
mib := []int32{6, 11, 0}
var sd sensordev
var idx int
var i int32
for i = 0; ; i++ {
mib[2] = i
e := sysctl(mib, unsafe.Pointer(&sd), unsafe.Sizeof(sd))
if e != 0 {
if e == unix.ENXIO {
continue
}
if e == unix.ENOENT {
break
}
}
if bytes.HasPrefix(sd.xname[:], []byte("acpibat")) {
var err error
if e != 0 {
err = e
}
if cb(sd, idx, err) {
return
}
idx++
}
}
}
func getBattery(sd sensordev) (*Battery, error) {
b := &Battery{}
e := ErrPartial{
Design: errValueNotFound,
Full: errValueNotFound,
Current: errValueNotFound,
ChargeRate: errValueNotFound,
State: errValueNotFound,
Voltage: errValueNotFound,
DesignVoltage: errValueNotFound,
}
mib := []int32{6, 11, sd.num, 0, 0}
for _, w := range sensorW {
mib[3] = w
readValues(mib, sd.maxnumt[w], map[string]*interValue{
"rate": {v: &b.ChargeRate, e: &e.ChargeRate},
"design capacity": {v: &b.Design, e: &e.Design},
"last full capacity": {v: &b.Full, e: &e.Full},
"remaining capacity": {v: &b.Current, e: &e.Current},
"current voltage": {v: &b.Voltage, e: &e.Voltage},
"voltage": {v: &b.DesignVoltage, e: &e.DesignVoltage},
"state": {s: &b.State, e: &e.State},
})
}
if e.DesignVoltage != nil && e.Voltage == nil {
b.DesignVoltage, e.DesignVoltage = b.Voltage, nil
}
if e.ChargeRate == errValueNotFound {
if e.Voltage == nil {
mib[3] = sensorA
readValues(mib, sd.maxnumt[sensorA], map[string]*interValue{
"rate": {v: &b.ChargeRate, e: &e.ChargeRate},
})
b.ChargeRate *= b.Voltage
} else {
e.ChargeRate = e.Voltage
}
}
if e.Design == errValueNotFound || e.Full == errValueNotFound || e.Current == errValueNotFound {
mib[3] = sensorAH
readValues(mib, sd.maxnumt[sensorAH], map[string]*interValue{
"design capacity": {v: &b.Design, e: &e.Design},
"last full capacity": {v: &b.Full, e: &e.Full},
"remaining capacity": {v: &b.Current, e: &e.Current},
})
b.Design *= b.DesignVoltage
b.Full *= b.Voltage
b.Current *= b.Voltage
}
return b, e
}
func systemGet(idx int) (*Battery, error) {
var b *Battery
var e error
sensordevIter(func(sd sensordev, i int, err error) bool {
if i == idx {
if err == nil {
b, e = getBattery(sd)
} else {
e = err
}
return true
}
return false
})
if b == nil {
return nil, ErrNotFound
}
return b, e
}
func systemGetAll() ([]*Battery, error) {
var batteries []*Battery
var errors Errors
sensordevIter(func(sd sensordev, i int, err error) bool {
var b *Battery
if err == nil {
b, err = getBattery(sd)
}
batteries = append(batteries, b)
errors = append(errors, err)
return false
})
return batteries, errors
}

258
vendor/github.com/distatus/battery/battery_solaris.go generated vendored Normal file
View File

@ -0,0 +1,258 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package battery
import (
"bufio"
"bytes"
"fmt"
"io"
"math"
"os/exec"
"strconv"
)
var errValueNotFound = fmt.Errorf("Value not found")
func readFloat(val string) (float64, error) {
num, err := strconv.ParseFloat(val, 64)
if err != nil {
return 0, err
}
if num == math.MaxUint32 {
return 0, fmt.Errorf("Unknown value received")
}
return num, nil
}
func readVoltage(val string) (float64, error) {
voltage, err := readFloat(val)
if err != nil {
return 0, err
}
return voltage / 1000, nil
}
func readState(val string) (State, error) {
state, err := strconv.Atoi(val)
if err != nil {
return Unknown, err
}
switch {
case state&1 != 0:
return newState("Discharging")
case state&2 != 0:
return newState("Charging")
case state&4 != 0:
return newState("Empty")
default:
return Unknown, fmt.Errorf("Invalid state flag retrieved: `%d`", state)
}
}
type errParse int
func (p errParse) Error() string {
return fmt.Sprintf("Parse error: `%d`", p)
}
type batteryReader struct {
cmdout *bufio.Scanner
li int
lline []byte
e ErrPartial
}
func (r *batteryReader) setErrParse(n int) {
if r.e.Design == errValueNotFound {
r.e.Design = errParse(n)
}
if r.e.Full == errValueNotFound {
r.e.Full = errParse(n)
}
if r.e.Current == errValueNotFound {
r.e.Current = errParse(n)
}
if r.e.ChargeRate == errValueNotFound {
r.e.ChargeRate = errParse(n)
}
if r.e.State == errValueNotFound {
r.e.State = errParse(n)
}
if r.e.Voltage == errValueNotFound {
r.e.Voltage = errParse(n)
}
if r.e.DesignVoltage == errValueNotFound {
r.e.DesignVoltage = errParse(n)
}
}
func (r *batteryReader) readValue() (string, string, int) {
var piece []byte
if r.lline != nil {
piece = r.lline
r.lline = nil
} else {
pieces := bytes.Split(r.cmdout.Bytes(), []byte{':'})
if len(pieces) < 4 {
return "", "", 4
}
i, err := strconv.Atoi(string(pieces[1]))
if err != nil {
return "", "", 1
}
if i != r.li {
r.li = i
r.lline = pieces[3]
return "", "", 666
}
piece = pieces[3]
}
values := bytes.Split(piece, []byte{'\t'})
if len(values) < 2 {
return "", "", 2
}
return string(values[0]), string(values[1]), 0
}
func (r *batteryReader) readBattery() (*Battery, bool, bool) {
b := &Battery{}
var exists, amps bool
for r.cmdout.Scan() {
exists = true
name, value, errno := r.readValue()
if errno == 666 {
break
}
if errno != 0 {
r.setErrParse(errno)
continue
}
switch name {
case "bif_design_cap":
b.Design, r.e.Design = readFloat(value)
case "bif_last_cap":
b.Full, r.e.Full = readFloat(value)
case "bif_unit":
amps = value != "0"
case "bif_voltage":
b.DesignVoltage, r.e.DesignVoltage = readVoltage(value)
case "bst_voltage":
b.Voltage, r.e.Voltage = readVoltage(value)
case "bst_rem_cap":
b.Current, r.e.Current = readFloat(value)
case "bst_rate":
b.ChargeRate, r.e.ChargeRate = readFloat(value)
case "bst_state":
b.State, r.e.State = readState(value)
}
}
return b, amps, exists
}
func (r *batteryReader) next() (*Battery, error) {
r.e = ErrPartial{
Design: errValueNotFound,
Full: errValueNotFound,
Current: errValueNotFound,
ChargeRate: errValueNotFound,
State: errValueNotFound,
Voltage: errValueNotFound,
DesignVoltage: errValueNotFound,
}
b, amps, exists := r.readBattery()
if !exists {
return nil, io.EOF
}
if r.e.DesignVoltage != nil && r.e.Voltage == nil {
b.DesignVoltage, r.e.DesignVoltage = b.Voltage, nil
}
if amps {
if r.e.DesignVoltage == nil {
b.Design *= b.DesignVoltage
} else {
r.e.Design = r.e.DesignVoltage
}
if r.e.Voltage == nil {
b.Full *= b.Voltage
b.Current *= b.Voltage
b.ChargeRate *= b.Voltage
} else {
r.e.Full = r.e.Voltage
r.e.Current = r.e.Voltage
r.e.ChargeRate = r.e.Voltage
}
}
if b.State == Unknown && r.e.Current == nil && r.e.Full == nil && b.Current >= b.Full {
b.State, r.e.State = newState("Full")
}
return b, r.e
}
func newBatteryReader() (*batteryReader, error) {
out, err := exec.Command("kstat", "-p", "-m", "acpi_drv", "-n", "battery B*").Output()
if err != nil {
return nil, err
}
return &batteryReader{cmdout: bufio.NewScanner(bytes.NewReader(out))}, nil
}
func systemGet(idx int) (*Battery, error) {
br, err := newBatteryReader()
if err != nil {
return nil, err
}
return br.next()
}
func systemGetAll() ([]*Battery, error) {
br, err := newBatteryReader()
if err != nil {
return nil, err
}
var batteries []*Battery
var errors Errors
for b, e := br.next(); e != io.EOF; b, e = br.next() {
batteries = append(batteries, b)
errors = append(errors, e)
}
return batteries, errors
}

318
vendor/github.com/distatus/battery/battery_windows.go generated vendored Normal file
View File

@ -0,0 +1,318 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package battery
import (
"errors"
"math"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type batteryQueryInformation struct {
BatteryTag uint32
InformationLevel int32
AtRate int32
}
type batteryInformation struct {
Capabilities uint32
Technology uint8
Reserved [3]uint8
Chemistry [4]uint8
DesignedCapacity uint32
FullChargedCapacity uint32
DefaultAlert1 uint32
DefaultAlert2 uint32
CriticalBias uint32
CycleCount uint32
}
type batteryWaitStatus struct {
BatteryTag uint32
Timeout uint32
PowerState uint32
LowCapacity uint32
HighCapacity uint32
}
type batteryStatus struct {
PowerState uint32
Capacity uint32
Voltage uint32
Rate int32
}
type guid struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
type spDeviceInterfaceData struct {
cbSize uint32
InterfaceClassGuid guid
Flags uint32
Reserved uint
}
var guidDeviceBattery = guid{
0x72631e54,
0x78A4,
0x11d0,
[8]byte{0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a},
}
func int32ToFloat64(num int32) (float64, error) {
// There is something wrong with this constant, but
// it appears to work so far...
if num == -0x80000000 { // BATTERY_UNKNOWN_RATE
return 0, errors.New("Unknown value received")
}
return math.Abs(float64(num)), nil
}
func uint32ToFloat64(num uint32) (float64, error) {
if num == 0xffffffff { // BATTERY_UNKNOWN_CAPACITY
return 0, errors.New("Unknown value received")
}
return float64(num), nil
}
func setupDiSetup(proc *windows.LazyProc, nargs, a1, a2, a3, a4, a5, a6 uintptr) (uintptr, error) {
r1, _, errno := syscall.Syscall6(proc.Addr(), nargs, a1, a2, a3, a4, a5, a6)
if windows.Handle(r1) == windows.InvalidHandle {
if errno != 0 {
return 0, error(errno)
}
return 0, syscall.EINVAL
}
return r1, nil
}
func setupDiCall(proc *windows.LazyProc, nargs, a1, a2, a3, a4, a5, a6 uintptr) syscall.Errno {
r1, _, errno := syscall.Syscall6(proc.Addr(), nargs, a1, a2, a3, a4, a5, a6)
if r1 == 0 {
if errno != 0 {
return errno
}
return syscall.EINVAL
}
return 0
}
var setupapi = &windows.LazyDLL{Name: "setupapi.dll", System: true}
var setupDiGetClassDevsW = setupapi.NewProc("SetupDiGetClassDevsW")
var setupDiEnumDeviceInterfaces = setupapi.NewProc("SetupDiEnumDeviceInterfaces")
var setupDiGetDeviceInterfaceDetailW = setupapi.NewProc("SetupDiGetDeviceInterfaceDetailW")
var setupDiDestroyDeviceInfoList = setupapi.NewProc("SetupDiDestroyDeviceInfoList")
func readState(powerState uint32) State {
switch powerState {
case 0x00000004:
return Charging
case 0x00000008:
return Empty
case 0x00000002:
return Discharging
case 0x00000001:
return Full
default:
return Unknown
}
}
func systemGet(idx int) (*Battery, error) {
hdev, err := setupDiSetup(
setupDiGetClassDevsW,
4,
uintptr(unsafe.Pointer(&guidDeviceBattery)),
0,
0,
2|16, // DIGCF_PRESENT|DIGCF_DEVICEINTERFACE
0, 0,
)
if err != nil {
return nil, err
}
defer syscall.Syscall(setupDiDestroyDeviceInfoList.Addr(), 1, hdev, 0, 0)
var did spDeviceInterfaceData
did.cbSize = uint32(unsafe.Sizeof(did))
errno := setupDiCall(
setupDiEnumDeviceInterfaces,
5,
hdev,
0,
uintptr(unsafe.Pointer(&guidDeviceBattery)),
uintptr(idx),
uintptr(unsafe.Pointer(&did)),
0,
)
if errno == 259 { // ERROR_NO_MORE_ITEMS
return nil, ErrNotFound
}
if errno != 0 {
return nil, errno
}
var cbRequired uint32
errno = setupDiCall(
setupDiGetDeviceInterfaceDetailW,
6,
hdev,
uintptr(unsafe.Pointer(&did)),
0,
0,
uintptr(unsafe.Pointer(&cbRequired)),
0,
)
if errno != 0 && errno != 122 { // ERROR_INSUFFICIENT_BUFFER
return nil, errno
}
// The god damn struct with ANYSIZE_ARRAY of utf16 in it is crazy.
// So... let's emulate it with array of uint16 ;-D.
// Keep in mind that the first two elements are actually cbSize.
didd := make([]uint16, cbRequired/2-1)
cbSize := (*uint32)(unsafe.Pointer(&didd[0]))
if unsafe.Sizeof(uint(0)) == 8 {
*cbSize = 8
} else {
*cbSize = 6
}
errno = setupDiCall(
setupDiGetDeviceInterfaceDetailW,
6,
hdev,
uintptr(unsafe.Pointer(&did)),
uintptr(unsafe.Pointer(&didd[0])),
uintptr(cbRequired),
uintptr(unsafe.Pointer(&cbRequired)),
0,
)
if errno != 0 {
return nil, errno
}
devicePath := &didd[2:][0]
handle, err := windows.CreateFile(
devicePath,
windows.GENERIC_READ|windows.GENERIC_WRITE,
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE,
nil,
windows.OPEN_EXISTING,
windows.FILE_ATTRIBUTE_NORMAL,
0,
)
if err != nil {
return nil, err
}
defer windows.CloseHandle(handle)
var dwOut uint32
var dwWait uint32
var bqi batteryQueryInformation
err = windows.DeviceIoControl(
handle,
2703424, // IOCTL_BATTERY_QUERY_TAG
(*byte)(unsafe.Pointer(&dwWait)),
uint32(unsafe.Sizeof(dwWait)),
(*byte)(unsafe.Pointer(&bqi.BatteryTag)),
uint32(unsafe.Sizeof(bqi.BatteryTag)),
&dwOut,
nil,
)
if err != nil {
return nil, err
}
if bqi.BatteryTag == 0 {
return nil, errors.New("BatteryTag not returned")
}
b := &Battery{}
e := ErrPartial{}
var bi batteryInformation
err = windows.DeviceIoControl(
handle,
2703428, // IOCTL_BATTERY_QUERY_INFORMATION
(*byte)(unsafe.Pointer(&bqi)),
uint32(unsafe.Sizeof(bqi)),
(*byte)(unsafe.Pointer(&bi)),
uint32(unsafe.Sizeof(bi)),
&dwOut,
nil,
)
if err == nil {
b.Full = float64(bi.FullChargedCapacity)
b.Design = float64(bi.DesignedCapacity)
} else {
e.Full = err
e.Design = err
}
bws := batteryWaitStatus{BatteryTag: bqi.BatteryTag}
var bs batteryStatus
err = windows.DeviceIoControl(
handle,
2703436, // IOCTL_BATTERY_QUERY_STATUS
(*byte)(unsafe.Pointer(&bws)),
uint32(unsafe.Sizeof(bws)),
(*byte)(unsafe.Pointer(&bs)),
uint32(unsafe.Sizeof(bs)),
&dwOut,
nil,
)
if err == nil {
b.Current, e.Current = uint32ToFloat64(bs.Capacity)
b.ChargeRate, e.ChargeRate = int32ToFloat64(bs.Rate)
b.Voltage, e.Voltage = uint32ToFloat64(bs.Voltage)
b.Voltage /= 1000
b.State = readState(bs.PowerState)
} else {
e.Current = err
e.ChargeRate = err
e.Voltage = err
e.State = err
}
b.DesignVoltage, e.DesignVoltage = b.Voltage, e.Voltage
return b, e
}
func systemGetAll() ([]*Battery, error) {
var batteries []*Battery
var errors Errors
for i := 0; ; i++ {
b, err := systemGet(i)
if err == ErrNotFound {
break
}
batteries = append(batteries, b)
errors = append(errors, err)
}
return batteries, errors
}

147
vendor/github.com/distatus/battery/errors.go generated vendored Normal file
View File

@ -0,0 +1,147 @@
// battery
// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package battery
import "fmt"
// ErrNotFound variable represents battery not found error.
//
// Only ever returned wrapped in ErrFatal.
var ErrNotFound = fmt.Errorf("Not found")
// ErrAllNotNil variable says that backend returned ErrPartial with
// all fields having not nil values, hence it was converted to ErrFatal.
//
// Only ever returned wrapped in ErrFatal.
var ErrAllNotNil = fmt.Errorf("All fields had not nil errors")
// ErrFatal type represents a fatal error.
//
// It indicates that either the library was not able to perform some kind
// of operation critical to retrieving any data, or all partials have failed at
// once (which would be equivalent to returning a ErrPartial with no nils).
//
// As such, the caller should assume that no meaningful data was
// returned alongside the error and act accordingly.
type ErrFatal struct {
Err error // The actual error that happened.
}
func (f ErrFatal) Error() string {
return fmt.Sprintf("Could not retrieve battery info: `%s`", f.Err)
}
// ErrPartial type represents a partial error.
//
// It indicates that there were problems retrieving some of the data,
// but some was also retrieved successfully.
// If there would be all nils, nil is returned instead.
// If there would be all not nils, ErrFatal is returned instead.
//
// The fields represent fields in the Battery type.
type ErrPartial struct {
State error
Current error
Full error
Design error
ChargeRate error
Voltage error
DesignVoltage error
}
func (p ErrPartial) Error() string {
if p.isNil() {
return "{}"
}
errors := map[string]error{
"State": p.State,
"Current": p.Current,
"Full": p.Full,
"Design": p.Design,
"ChargeRate": p.ChargeRate,
"Voltage": p.Voltage,
"DesignVoltage": p.DesignVoltage,
}
keys := []string{"State", "Current", "Full", "Design", "ChargeRate", "Voltage", "DesignVoltage"}
s := "{"
for _, name := range keys {
err := errors[name]
if err != nil {
s += fmt.Sprintf("%s:%s ", name, err.Error())
}
}
return s[:len(s)-1] + "}"
}
func (p ErrPartial) isNil() bool {
return p.State == nil &&
p.Current == nil &&
p.Full == nil &&
p.Design == nil &&
p.ChargeRate == nil &&
p.Voltage == nil &&
p.DesignVoltage == nil
}
func (p ErrPartial) noNil() bool {
return p.State != nil &&
p.Current != nil &&
p.Full != nil &&
p.Design != nil &&
p.ChargeRate != nil &&
p.Voltage != nil &&
p.DesignVoltage != nil
}
// Errors type represents an array of ErrFatal, ErrPartial or nil values.
//
// Can only possibly be returned by GetAll() call.
type Errors []error
func (e Errors) Error() string {
s := "["
for _, err := range e {
if err != nil {
s += err.Error() + " "
}
}
if len(s) > 1 {
s = s[:len(s)-1]
}
return s + "]"
}
func wrapError(err error) error {
if perr, ok := err.(ErrPartial); ok {
if perr.isNil() {
return nil
}
if perr.noNil() {
return ErrFatal{ErrAllNotNil}
}
return perr
}
if err != nil {
return ErrFatal{err}
}
return nil
}

48
vendor/github.com/distatus/battery/ioctl.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
// battery
// Copyright (C) 2016 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// +build freebsd dragonfly netbsd
package battery
import (
"unsafe"
"golang.org/x/sys/unix"
)
func ioctl(fd int, nr int64, typ byte, size uintptr, retptr unsafe.Pointer) error {
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
// Some magicks derived from sys/ioccom.h.
uintptr((0x40000000|0x80000000)|
((int64(size)&(1<<13-1))<<16)|
(int64(typ)<<8)|
nr,
),
uintptr(retptr),
)
if errno != 0 {
return errno
}
return nil
}

25
vendor/github.com/docopt/docopt.go/.gitignore generated vendored Normal file
View File

@ -0,0 +1,25 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
# coverage droppings
profile.cov

32
vendor/github.com/docopt/docopt.go/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,32 @@
# Travis CI (http://travis-ci.org/) is a continuous integration
# service for open source projects. This file configures it
# to run unit tests for docopt-go.
language: go
go:
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- tip
matrix:
fast_finish: true
before_install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
install:
- go get -d -v ./... && go build -v ./...
script:
- go vet -x ./...
- go test -v ./...
- go test -covermode=count -coverprofile=profile.cov .
after_script:
- $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci

21
vendor/github.com/docopt/docopt.go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Keith Batten
Copyright (c) 2016 David Irvine
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

116
vendor/github.com/docopt/docopt.go/README.md generated vendored Normal file
View File

@ -0,0 +1,116 @@
docopt-go
=========
[![Build Status](https://travis-ci.org/docopt/docopt.go.svg?branch=master)](https://travis-ci.org/docopt/docopt.go)
[![Coverage Status](https://coveralls.io/repos/github/docopt/docopt.go/badge.svg)](https://coveralls.io/github/docopt/docopt.go)
[![GoDoc](https://godoc.org/github.com/docopt/docopt.go?status.svg)](https://godoc.org/github.com/docopt/docopt.go)
An implementation of [docopt](http://docopt.org/) in the [Go](http://golang.org/) programming language.
**docopt** helps you create *beautiful* command-line interfaces easily:
```go
package main
import (
"fmt"
"github.com/docopt/docopt-go"
)
func main() {
usage := `Naval Fate.
Usage:
naval_fate ship new <name>...
naval_fate ship <name> move <x> <y> [--speed=<kn>]
naval_fate ship shoot <x> <y>
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
naval_fate -h | --help
naval_fate --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.`
arguments, _ := docopt.ParseDoc(usage)
fmt.Println(arguments)
}
```
**docopt** parses command-line arguments based on a help message. Don't write parser code: a good help message already has all the necessary information in it.
## Installation
⚠ Use the alias "docopt-go". To use docopt in your Go code:
```go
import "github.com/docopt/docopt-go"
```
To install docopt in your `$GOPATH`:
```console
$ go get github.com/docopt/docopt-go
```
## API
Given a conventional command-line help message, docopt processes the arguments. See https://github.com/docopt/docopt#help-message-format for a description of the help message format.
This package exposes three different APIs, depending on the level of control required. The first, simplest way to parse your docopt usage is to just call:
```go
docopt.ParseDoc(usage)
```
This will use `os.Args[1:]` as the argv slice, and use the default parser options. If you want to provide your own version string and args, then use:
```go
docopt.ParseArgs(usage, argv, "1.2.3")
```
If the last parameter (version) is a non-empty string, it will be printed when `--version` is given in the argv slice. Finally, we can instantiate our own `docopt.Parser` which gives us control over how things like help messages are printed and whether to exit after displaying usage messages, etc.
```go
parser := &docopt.Parser{
HelpHandler: docopt.PrintHelpOnly,
OptionsFirst: true,
}
opts, err := parser.ParseArgs(usage, argv, "")
```
In particular, setting your own custom `HelpHandler` function makes unit testing your own docs with example command line invocations much more enjoyable.
All three of these return a map of option names to the values parsed from argv, and an error or nil. You can get the values using the helpers, or just treat it as a regular map:
```go
flag, _ := opts.Bool("--flag")
secs, _ := opts.Int("<seconds>")
```
Additionally, you can `Bind` these to a struct, assigning option values to the
exported fields of that struct, all at once.
```go
var config struct {
Command string `docopt:"<cmd>"`
Tries int `docopt:"-n"`
Force bool // Gets the value of --force
}
opts.Bind(&config)
```
More documentation is available at [godoc.org](https://godoc.org/github.com/docopt/docopt-go).
## Unit Testing
Unit testing your own usage docs is recommended, so you can be sure that for a given command line invocation, the expected options are set. An example of how to do this is [in the examples folder](examples/unit_test/unit_test.go).
## Tests
All tests from the Python version are implemented and passing at [Travis CI](https://travis-ci.org/docopt/docopt-go). New language-agnostic tests have been added to [test_golang.docopt](test_golang.docopt).
To run tests for docopt-go, use `go test`.

49
vendor/github.com/docopt/docopt.go/doc.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
/*
Package docopt parses command-line arguments based on a help message.
Given a conventional command-line help message, docopt processes the arguments.
See https://github.com/docopt/docopt#help-message-format for a description of
the help message format.
This package exposes three different APIs, depending on the level of control
required. The first, simplest way to parse your docopt usage is to just call:
docopt.ParseDoc(usage)
This will use os.Args[1:] as the argv slice, and use the default parser
options. If you want to provide your own version string and args, then use:
docopt.ParseArgs(usage, argv, "1.2.3")
If the last parameter (version) is a non-empty string, it will be printed when
--version is given in the argv slice. Finally, we can instantiate our own
docopt.Parser which gives us control over how things like help messages are
printed and whether to exit after displaying usage messages, etc.
parser := &docopt.Parser{
HelpHandler: docopt.PrintHelpOnly,
OptionsFirst: true,
}
opts, err := parser.ParseArgs(usage, argv, "")
In particular, setting your own custom HelpHandler function makes unit testing
your own docs with example command line invocations much more enjoyable.
All three of these return a map of option names to the values parsed from argv,
and an error or nil. You can get the values using the helpers, or just treat it
as a regular map:
flag, _ := opts.Bool("--flag")
secs, _ := opts.Int("<seconds>")
Additionally, you can `Bind` these to a struct, assigning option values to the
exported fields of that struct, all at once.
var config struct {
Command string `docopt:"<cmd>"`
Tries int `docopt:"-n"`
Force bool // Gets the value of --force
}
opts.Bind(&config)
*/
package docopt

575
vendor/github.com/docopt/docopt.go/docopt.go generated vendored Normal file
View File

@ -0,0 +1,575 @@
// Licensed under terms of MIT license (see LICENSE-MIT)
// Copyright (c) 2013 Keith Batten, kbatten@gmail.com
// Copyright (c) 2016 David Irvine
package docopt
import (
"fmt"
"os"
"regexp"
"strings"
)
type Parser struct {
// HelpHandler is called when we encounter bad user input, or when the user
// asks for help.
// By default, this calls os.Exit(0) if it handled a built-in option such
// as -h, --help or --version. If the user errored with a wrong command or
// options, we exit with a return code of 1.
HelpHandler func(err error, usage string)
// OptionsFirst requires that option flags always come before positional
// arguments; otherwise they can overlap.
OptionsFirst bool
// SkipHelpFlags tells the parser not to look for -h and --help flags and
// call the HelpHandler.
SkipHelpFlags bool
}
var PrintHelpAndExit = func(err error, usage string) {
if err != nil {
fmt.Fprintln(os.Stderr, usage)
os.Exit(1)
} else {
fmt.Println(usage)
os.Exit(0)
}
}
var PrintHelpOnly = func(err error, usage string) {
if err != nil {
fmt.Fprintln(os.Stderr, usage)
} else {
fmt.Println(usage)
}
}
var NoHelpHandler = func(err error, usage string) {}
var DefaultParser = &Parser{
HelpHandler: PrintHelpAndExit,
OptionsFirst: false,
SkipHelpFlags: false,
}
// ParseDoc parses os.Args[1:] based on the interface described in doc, using the default parser options.
func ParseDoc(doc string) (Opts, error) {
return ParseArgs(doc, nil, "")
}
// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
// string, then this will be displayed when the --version flag is found. This method uses the default parser options.
func ParseArgs(doc string, argv []string, version string) (Opts, error) {
return DefaultParser.ParseArgs(doc, argv, version)
}
// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
// string, then this will be displayed when the --version flag is found.
func (p *Parser) ParseArgs(doc string, argv []string, version string) (Opts, error) {
return p.parse(doc, argv, version)
}
// Deprecated: Parse is provided for backward compatibility with the original docopt.go package.
// Please rather make use of ParseDoc, ParseArgs, or use your own custom Parser.
func Parse(doc string, argv []string, help bool, version string, optionsFirst bool, exit ...bool) (map[string]interface{}, error) {
exitOk := true
if len(exit) > 0 {
exitOk = exit[0]
}
p := &Parser{
OptionsFirst: optionsFirst,
SkipHelpFlags: !help,
}
if exitOk {
p.HelpHandler = PrintHelpAndExit
} else {
p.HelpHandler = PrintHelpOnly
}
return p.parse(doc, argv, version)
}
func (p *Parser) parse(doc string, argv []string, version string) (map[string]interface{}, error) {
if argv == nil {
argv = os.Args[1:]
}
if p.HelpHandler == nil {
p.HelpHandler = DefaultParser.HelpHandler
}
args, output, err := parse(doc, argv, !p.SkipHelpFlags, version, p.OptionsFirst)
if _, ok := err.(*UserError); ok {
// the user gave us bad input
p.HelpHandler(err, output)
} else if len(output) > 0 && err == nil {
// the user asked for help or --version
p.HelpHandler(err, output)
}
return args, err
}
// -----------------------------------------------------------------------------
// parse and return a map of args, output and all errors
func parse(doc string, argv []string, help bool, version string, optionsFirst bool) (args map[string]interface{}, output string, err error) {
if argv == nil && len(os.Args) > 1 {
argv = os.Args[1:]
}
usageSections := parseSection("usage:", doc)
if len(usageSections) == 0 {
err = newLanguageError("\"usage:\" (case-insensitive) not found.")
return
}
if len(usageSections) > 1 {
err = newLanguageError("More than one \"usage:\" (case-insensitive).")
return
}
usage := usageSections[0]
options := parseDefaults(doc)
formal, err := formalUsage(usage)
if err != nil {
output = handleError(err, usage)
return
}
pat, err := parsePattern(formal, &options)
if err != nil {
output = handleError(err, usage)
return
}
patternArgv, err := parseArgv(newTokenList(argv, errorUser), &options, optionsFirst)
if err != nil {
output = handleError(err, usage)
return
}
patFlat, err := pat.flat(patternOption)
if err != nil {
output = handleError(err, usage)
return
}
patternOptions := patFlat.unique()
patFlat, err = pat.flat(patternOptionSSHORTCUT)
if err != nil {
output = handleError(err, usage)
return
}
for _, optionsShortcut := range patFlat {
docOptions := parseDefaults(doc)
optionsShortcut.children = docOptions.unique().diff(patternOptions)
}
if output = extras(help, version, patternArgv, doc); len(output) > 0 {
return
}
err = pat.fix()
if err != nil {
output = handleError(err, usage)
return
}
matched, left, collected := pat.match(&patternArgv, nil)
if matched && len(*left) == 0 {
patFlat, err = pat.flat(patternDefault)
if err != nil {
output = handleError(err, usage)
return
}
args = append(patFlat, *collected...).dictionary()
return
}
err = newUserError("")
output = handleError(err, usage)
return
}
func handleError(err error, usage string) string {
if _, ok := err.(*UserError); ok {
return strings.TrimSpace(fmt.Sprintf("%s\n%s", err, usage))
}
return ""
}
func parseSection(name, source string) []string {
p := regexp.MustCompile(`(?im)^([^\n]*` + name + `[^\n]*\n?(?:[ \t].*?(?:\n|$))*)`)
s := p.FindAllString(source, -1)
if s == nil {
s = []string{}
}
for i, v := range s {
s[i] = strings.TrimSpace(v)
}
return s
}
func parseDefaults(doc string) patternList {
defaults := patternList{}
p := regexp.MustCompile(`\n[ \t]*(-\S+?)`)
for _, s := range parseSection("options:", doc) {
// FIXME corner case "bla: options: --foo"
_, _, s = stringPartition(s, ":") // get rid of "options:"
split := p.Split("\n"+s, -1)[1:]
match := p.FindAllStringSubmatch("\n"+s, -1)
for i := range split {
optionDescription := match[i][1] + split[i]
if strings.HasPrefix(optionDescription, "-") {
defaults = append(defaults, parseOption(optionDescription))
}
}
}
return defaults
}
func parsePattern(source string, options *patternList) (*pattern, error) {
tokens := tokenListFromPattern(source)
result, err := parseExpr(tokens, options)
if err != nil {
return nil, err
}
if tokens.current() != nil {
return nil, tokens.errorFunc("unexpected ending: %s" + strings.Join(tokens.tokens, " "))
}
return newRequired(result...), nil
}
func parseArgv(tokens *tokenList, options *patternList, optionsFirst bool) (patternList, error) {
/*
Parse command-line argument vector.
If options_first:
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
else:
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
*/
parsed := patternList{}
for tokens.current() != nil {
if tokens.current().eq("--") {
for _, v := range tokens.tokens {
parsed = append(parsed, newArgument("", v))
}
return parsed, nil
} else if tokens.current().hasPrefix("--") {
pl, err := parseLong(tokens, options)
if err != nil {
return nil, err
}
parsed = append(parsed, pl...)
} else if tokens.current().hasPrefix("-") && !tokens.current().eq("-") {
ps, err := parseShorts(tokens, options)
if err != nil {
return nil, err
}
parsed = append(parsed, ps...)
} else if optionsFirst {
for _, v := range tokens.tokens {
parsed = append(parsed, newArgument("", v))
}
return parsed, nil
} else {
parsed = append(parsed, newArgument("", tokens.move().String()))
}
}
return parsed, nil
}
func parseOption(optionDescription string) *pattern {
optionDescription = strings.TrimSpace(optionDescription)
options, _, description := stringPartition(optionDescription, " ")
options = strings.Replace(options, ",", " ", -1)
options = strings.Replace(options, "=", " ", -1)
short := ""
long := ""
argcount := 0
var value interface{}
value = false
reDefault := regexp.MustCompile(`(?i)\[default: (.*)\]`)
for _, s := range strings.Fields(options) {
if strings.HasPrefix(s, "--") {
long = s
} else if strings.HasPrefix(s, "-") {
short = s
} else {
argcount = 1
}
if argcount > 0 {
matched := reDefault.FindAllStringSubmatch(description, -1)
if len(matched) > 0 {
value = matched[0][1]
} else {
value = nil
}
}
}
return newOption(short, long, argcount, value)
}
func parseExpr(tokens *tokenList, options *patternList) (patternList, error) {
// expr ::= seq ( '|' seq )* ;
seq, err := parseSeq(tokens, options)
if err != nil {
return nil, err
}
if !tokens.current().eq("|") {
return seq, nil
}
var result patternList
if len(seq) > 1 {
result = patternList{newRequired(seq...)}
} else {
result = seq
}
for tokens.current().eq("|") {
tokens.move()
seq, err = parseSeq(tokens, options)
if err != nil {
return nil, err
}
if len(seq) > 1 {
result = append(result, newRequired(seq...))
} else {
result = append(result, seq...)
}
}
if len(result) > 1 {
return patternList{newEither(result...)}, nil
}
return result, nil
}
func parseSeq(tokens *tokenList, options *patternList) (patternList, error) {
// seq ::= ( atom [ '...' ] )* ;
result := patternList{}
for !tokens.current().match(true, "]", ")", "|") {
atom, err := parseAtom(tokens, options)
if err != nil {
return nil, err
}
if tokens.current().eq("...") {
atom = patternList{newOneOrMore(atom...)}
tokens.move()
}
result = append(result, atom...)
}
return result, nil
}
func parseAtom(tokens *tokenList, options *patternList) (patternList, error) {
// atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ;
tok := tokens.current()
result := patternList{}
if tokens.current().match(false, "(", "[") {
tokens.move()
var matching string
pl, err := parseExpr(tokens, options)
if err != nil {
return nil, err
}
if tok.eq("(") {
matching = ")"
result = patternList{newRequired(pl...)}
} else if tok.eq("[") {
matching = "]"
result = patternList{newOptional(pl...)}
}
moved := tokens.move()
if !moved.eq(matching) {
return nil, tokens.errorFunc("unmatched '%s', expected: '%s' got: '%s'", tok, matching, moved)
}
return result, nil
} else if tok.eq("options") {
tokens.move()
return patternList{newOptionsShortcut()}, nil
} else if tok.hasPrefix("--") && !tok.eq("--") {
return parseLong(tokens, options)
} else if tok.hasPrefix("-") && !tok.eq("-") && !tok.eq("--") {
return parseShorts(tokens, options)
} else if tok.hasPrefix("<") && tok.hasSuffix(">") || tok.isUpper() {
return patternList{newArgument(tokens.move().String(), nil)}, nil
}
return patternList{newCommand(tokens.move().String(), false)}, nil
}
func parseLong(tokens *tokenList, options *patternList) (patternList, error) {
// long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
long, eq, v := stringPartition(tokens.move().String(), "=")
var value interface{}
var opt *pattern
if eq == "" && v == "" {
value = nil
} else {
value = v
}
if !strings.HasPrefix(long, "--") {
return nil, newError("long option '%s' doesn't start with --", long)
}
similar := patternList{}
for _, o := range *options {
if o.long == long {
similar = append(similar, o)
}
}
if tokens.err == errorUser && len(similar) == 0 { // if no exact match
similar = patternList{}
for _, o := range *options {
if strings.HasPrefix(o.long, long) {
similar = append(similar, o)
}
}
}
if len(similar) > 1 { // might be simply specified ambiguously 2+ times?
similarLong := make([]string, len(similar))
for i, s := range similar {
similarLong[i] = s.long
}
return nil, tokens.errorFunc("%s is not a unique prefix: %s?", long, strings.Join(similarLong, ", "))
} else if len(similar) < 1 {
argcount := 0
if eq == "=" {
argcount = 1
}
opt = newOption("", long, argcount, false)
*options = append(*options, opt)
if tokens.err == errorUser {
var val interface{}
if argcount > 0 {
val = value
} else {
val = true
}
opt = newOption("", long, argcount, val)
}
} else {
opt = newOption(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value)
if opt.argcount == 0 {
if value != nil {
return nil, tokens.errorFunc("%s must not have an argument", opt.long)
}
} else {
if value == nil {
if tokens.current().match(true, "--") {
return nil, tokens.errorFunc("%s requires argument", opt.long)
}
moved := tokens.move()
if moved != nil {
value = moved.String() // only set as string if not nil
}
}
}
if tokens.err == errorUser {
if value != nil {
opt.value = value
} else {
opt.value = true
}
}
}
return patternList{opt}, nil
}
func parseShorts(tokens *tokenList, options *patternList) (patternList, error) {
// shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;
tok := tokens.move()
if !tok.hasPrefix("-") || tok.hasPrefix("--") {
return nil, newError("short option '%s' doesn't start with -", tok)
}
left := strings.TrimLeft(tok.String(), "-")
parsed := patternList{}
for left != "" {
var opt *pattern
short := "-" + left[0:1]
left = left[1:]
similar := patternList{}
for _, o := range *options {
if o.short == short {
similar = append(similar, o)
}
}
if len(similar) > 1 {
return nil, tokens.errorFunc("%s is specified ambiguously %d times", short, len(similar))
} else if len(similar) < 1 {
opt = newOption(short, "", 0, false)
*options = append(*options, opt)
if tokens.err == errorUser {
opt = newOption(short, "", 0, true)
}
} else { // why copying is necessary here?
opt = newOption(short, similar[0].long, similar[0].argcount, similar[0].value)
var value interface{}
if opt.argcount > 0 {
if left == "" {
if tokens.current().match(true, "--") {
return nil, tokens.errorFunc("%s requires argument", short)
}
value = tokens.move().String()
} else {
value = left
left = ""
}
}
if tokens.err == errorUser {
if value != nil {
opt.value = value
} else {
opt.value = true
}
}
}
parsed = append(parsed, opt)
}
return parsed, nil
}
func formalUsage(section string) (string, error) {
_, _, section = stringPartition(section, ":") // drop "usage:"
pu := strings.Fields(section)
if len(pu) == 0 {
return "", newLanguageError("no fields found in usage (perhaps a spacing error).")
}
result := "( "
for _, s := range pu[1:] {
if s == pu[0] {
result += ") | ( "
} else {
result += s + " "
}
}
result += ")"
return result, nil
}
func extras(help bool, version string, options patternList, doc string) string {
if help {
for _, o := range options {
if (o.name == "-h" || o.name == "--help") && o.value == true {
return strings.Trim(doc, "\n")
}
}
}
if version != "" {
for _, o := range options {
if (o.name == "--version") && o.value == true {
return version
}
}
}
return ""
}
func stringPartition(s, sep string) (string, string, string) {
sepPos := strings.Index(s, sep)
if sepPos == -1 { // no seperator found
return s, "", ""
}
split := strings.SplitN(s, sep, 2)
return split[0], sep, split[1]
}

49
vendor/github.com/docopt/docopt.go/error.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
package docopt
import (
"fmt"
)
type errorType int
const (
errorUser errorType = iota
errorLanguage
)
func (e errorType) String() string {
switch e {
case errorUser:
return "errorUser"
case errorLanguage:
return "errorLanguage"
}
return ""
}
// UserError records an error with program arguments.
type UserError struct {
msg string
Usage string
}
func (e UserError) Error() string {
return e.msg
}
func newUserError(msg string, f ...interface{}) error {
return &UserError{fmt.Sprintf(msg, f...), ""}
}
// LanguageError records an error with the doc string.
type LanguageError struct {
msg string
}
func (e LanguageError) Error() string {
return e.msg
}
func newLanguageError(msg string, f ...interface{}) error {
return &LanguageError{fmt.Sprintf(msg, f...)}
}
var newError = fmt.Errorf

264
vendor/github.com/docopt/docopt.go/opts.go generated vendored Normal file
View File

@ -0,0 +1,264 @@
package docopt
import (
"fmt"
"reflect"
"strconv"
"strings"
"unicode"
)
func errKey(key string) error {
return fmt.Errorf("no such key: %q", key)
}
func errType(key string) error {
return fmt.Errorf("key: %q failed type conversion", key)
}
func errStrconv(key string, convErr error) error {
return fmt.Errorf("key: %q failed type conversion: %s", key, convErr)
}
// Opts is a map of command line options to their values, with some convenience
// methods for value type conversion (bool, float64, int, string). For example,
// to get an option value as an int:
//
// opts, _ := docopt.ParseDoc("Usage: sleep <seconds>")
// secs, _ := opts.Int("<seconds>")
//
// Additionally, Opts.Bind allows you easily populate a struct's fields with the
// values of each option value. See below for examples.
//
// Lastly, you can still treat Opts as a regular map, and do any type checking
// and conversion that you want to yourself. For example:
//
// if s, ok := opts["<binary>"].(string); ok {
// if val, err := strconv.ParseUint(s, 2, 64); err != nil { ... }
// }
//
// Note that any non-boolean option / flag will have a string value in the
// underlying map.
type Opts map[string]interface{}
func (o Opts) String(key string) (s string, err error) {
v, ok := o[key]
if !ok {
err = errKey(key)
return
}
s, ok = v.(string)
if !ok {
err = errType(key)
}
return
}
func (o Opts) Bool(key string) (b bool, err error) {
v, ok := o[key]
if !ok {
err = errKey(key)
return
}
b, ok = v.(bool)
if !ok {
err = errType(key)
}
return
}
func (o Opts) Int(key string) (i int, err error) {
s, err := o.String(key)
if err != nil {
return
}
i, err = strconv.Atoi(s)
if err != nil {
err = errStrconv(key, err)
}
return
}
func (o Opts) Float64(key string) (f float64, err error) {
s, err := o.String(key)
if err != nil {
return
}
f, err = strconv.ParseFloat(s, 64)
if err != nil {
err = errStrconv(key, err)
}
return
}
// Bind populates the fields of a given struct with matching option values.
// Each key in Opts will be mapped to an exported field of the struct pointed
// to by `v`, as follows:
//
// abc int // Unexported field, ignored
// Abc string // Mapped from `--abc`, `<abc>`, or `abc`
// // (case insensitive)
// A string // Mapped from `-a`, `<a>` or `a`
// // (case insensitive)
// Abc int `docopt:"XYZ"` // Mapped from `XYZ`
// Abc bool `docopt:"-"` // Mapped from `-`
// Abc bool `docopt:"-x,--xyz"` // Mapped from `-x` or `--xyz`
// // (first non-zero value found)
//
// Tagged (annotated) fields will always be mapped first. If no field is tagged
// with an option's key, Bind will try to map the option to an appropriately
// named field (as above).
//
// Bind also handles conversion to bool, float, int or string types.
func (o Opts) Bind(v interface{}) error {
structVal := reflect.ValueOf(v)
if structVal.Kind() != reflect.Ptr {
return newError("'v' argument is not pointer to struct type")
}
for structVal.Kind() == reflect.Ptr {
structVal = structVal.Elem()
}
if structVal.Kind() != reflect.Struct {
return newError("'v' argument is not pointer to struct type")
}
structType := structVal.Type()
tagged := make(map[string]int) // Tagged field tags
untagged := make(map[string]int) // Untagged field names
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
if isUnexportedField(field) || field.Anonymous {
continue
}
tag := field.Tag.Get("docopt")
if tag == "" {
untagged[field.Name] = i
continue
}
for _, t := range strings.Split(tag, ",") {
tagged[t] = i
}
}
// Get the index of the struct field to use, based on the option key.
// Second argument is true/false on whether something was matched.
getFieldIndex := func(key string) (int, bool) {
if i, ok := tagged[key]; ok {
return i, true
}
if i, ok := untagged[guessUntaggedField(key)]; ok {
return i, true
}
return -1, false
}
indexMap := make(map[string]int) // Option keys to field index
// Pre-check that option keys are mapped to fields and fields are zero valued, before populating them.
for k := range o {
i, ok := getFieldIndex(k)
if !ok {
if k == "--help" || k == "--version" { // Don't require these to be mapped.
continue
}
return newError("mapping of %q is not found in given struct, or is an unexported field", k)
}
fieldVal := structVal.Field(i)
zeroVal := reflect.Zero(fieldVal.Type())
if !reflect.DeepEqual(fieldVal.Interface(), zeroVal.Interface()) {
return newError("%q field is non-zero, will be overwritten by value of %q", structType.Field(i).Name, k)
}
indexMap[k] = i
}
// Populate fields with option values.
for k, v := range o {
i, ok := indexMap[k]
if !ok {
continue // Not mapped.
}
field := structVal.Field(i)
if !reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()) {
// The struct's field is already non-zero (by our doing), so don't change it.
// This happens with comma separated tags, e.g. `docopt:"-h,--help"` which is a
// convenient way of checking if one of multiple boolean flags are set.
continue
}
optVal := reflect.ValueOf(v)
// Option value is the zero Value, so we can't get its .Type(). No need to assign anyway, so move along.
if !optVal.IsValid() {
continue
}
if !field.CanSet() {
return newError("%q field cannot be set", structType.Field(i).Name)
}
// Try to assign now if able. bool and string values should be assignable already.
if optVal.Type().AssignableTo(field.Type()) {
field.Set(optVal)
continue
}
// Try to convert the value and assign if able.
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if x, err := o.Int(k); err == nil {
field.SetInt(int64(x))
continue
}
case reflect.Float32, reflect.Float64:
if x, err := o.Float64(k); err == nil {
field.SetFloat(x)
continue
}
}
// TODO: Something clever (recursive?) with non-string slices.
// case reflect.Slice:
// if optVal.Kind() == reflect.Slice {
// for i := 0; i < optVal.Len(); i++ {
// sliceVal := optVal.Index(i)
// fmt.Printf("%v", sliceVal)
// }
// fmt.Printf("\n")
// }
return newError("value of %q is not assignable to %q field", k, structType.Field(i).Name)
}
return nil
}
// isUnexportedField returns whether the field is unexported.
// isUnexportedField is to avoid the bug in versions older than Go1.3.
// See following links:
// https://code.google.com/p/go/issues/detail?id=7247
// http://golang.org/ref/spec#Exported_identifiers
func isUnexportedField(field reflect.StructField) bool {
return !(field.PkgPath == "" && unicode.IsUpper(rune(field.Name[0])))
}
// Convert a string like "--my-special-flag" to "MySpecialFlag".
func titleCaseDashes(key string) string {
nextToUpper := true
mapFn := func(r rune) rune {
if r == '-' {
nextToUpper = true
return -1
}
if nextToUpper {
nextToUpper = false
return unicode.ToUpper(r)
}
return r
}
return strings.Map(mapFn, key)
}
// Best guess which field.Name in a struct to assign for an option key.
func guessUntaggedField(key string) string {
switch {
case strings.HasPrefix(key, "--") && len(key[2:]) > 1:
return titleCaseDashes(key[2:])
case strings.HasPrefix(key, "-") && len(key[1:]) == 1:
return titleCaseDashes(key[1:])
case strings.HasPrefix(key, "<") && strings.HasSuffix(key, ">"):
key = key[1 : len(key)-1]
}
return strings.Title(strings.ToLower(key))
}

550
vendor/github.com/docopt/docopt.go/pattern.go generated vendored Normal file
View File

@ -0,0 +1,550 @@
package docopt
import (
"fmt"
"reflect"
"strings"
)
type patternType uint
const (
// leaf
patternArgument patternType = 1 << iota
patternCommand
patternOption
// branch
patternRequired
patternOptionAL
patternOptionSSHORTCUT // Marker/placeholder for [options] shortcut.
patternOneOrMore
patternEither
patternLeaf = patternArgument +
patternCommand +
patternOption
patternBranch = patternRequired +
patternOptionAL +
patternOptionSSHORTCUT +
patternOneOrMore +
patternEither
patternAll = patternLeaf + patternBranch
patternDefault = 0
)
func (pt patternType) String() string {
switch pt {
case patternArgument:
return "argument"
case patternCommand:
return "command"
case patternOption:
return "option"
case patternRequired:
return "required"
case patternOptionAL:
return "optional"
case patternOptionSSHORTCUT:
return "optionsshortcut"
case patternOneOrMore:
return "oneormore"
case patternEither:
return "either"
case patternLeaf:
return "leaf"
case patternBranch:
return "branch"
case patternAll:
return "all"
case patternDefault:
return "default"
}
return ""
}
type pattern struct {
t patternType
children patternList
name string
value interface{}
short string
long string
argcount int
}
type patternList []*pattern
func newBranchPattern(t patternType, pl ...*pattern) *pattern {
var p pattern
p.t = t
p.children = make(patternList, len(pl))
copy(p.children, pl)
return &p
}
func newRequired(pl ...*pattern) *pattern {
return newBranchPattern(patternRequired, pl...)
}
func newEither(pl ...*pattern) *pattern {
return newBranchPattern(patternEither, pl...)
}
func newOneOrMore(pl ...*pattern) *pattern {
return newBranchPattern(patternOneOrMore, pl...)
}
func newOptional(pl ...*pattern) *pattern {
return newBranchPattern(patternOptionAL, pl...)
}
func newOptionsShortcut() *pattern {
var p pattern
p.t = patternOptionSSHORTCUT
return &p
}
func newLeafPattern(t patternType, name string, value interface{}) *pattern {
// default: value=nil
var p pattern
p.t = t
p.name = name
p.value = value
return &p
}
func newArgument(name string, value interface{}) *pattern {
// default: value=nil
return newLeafPattern(patternArgument, name, value)
}
func newCommand(name string, value interface{}) *pattern {
// default: value=false
var p pattern
p.t = patternCommand
p.name = name
p.value = value
return &p
}
func newOption(short, long string, argcount int, value interface{}) *pattern {
// default: "", "", 0, false
var p pattern
p.t = patternOption
p.short = short
p.long = long
if long != "" {
p.name = long
} else {
p.name = short
}
p.argcount = argcount
if value == false && argcount > 0 {
p.value = nil
} else {
p.value = value
}
return &p
}
func (p *pattern) flat(types patternType) (patternList, error) {
if p.t&patternLeaf != 0 {
if types == patternDefault {
types = patternAll
}
if p.t&types != 0 {
return patternList{p}, nil
}
return patternList{}, nil
}
if p.t&patternBranch != 0 {
if p.t&types != 0 {
return patternList{p}, nil
}
result := patternList{}
for _, child := range p.children {
childFlat, err := child.flat(types)
if err != nil {
return nil, err
}
result = append(result, childFlat...)
}
return result, nil
}
return nil, newError("unknown pattern type: %d, %d", p.t, types)
}
func (p *pattern) fix() error {
err := p.fixIdentities(nil)
if err != nil {
return err
}
p.fixRepeatingArguments()
return nil
}
func (p *pattern) fixIdentities(uniq patternList) error {
// Make pattern-tree tips point to same object if they are equal.
if p.t&patternBranch == 0 {
return nil
}
if uniq == nil {
pFlat, err := p.flat(patternDefault)
if err != nil {
return err
}
uniq = pFlat.unique()
}
for i, child := range p.children {
if child.t&patternBranch == 0 {
ind, err := uniq.index(child)
if err != nil {
return err
}
p.children[i] = uniq[ind]
} else {
err := child.fixIdentities(uniq)
if err != nil {
return err
}
}
}
return nil
}
func (p *pattern) fixRepeatingArguments() {
// Fix elements that should accumulate/increment values.
var either []patternList
for _, child := range p.transform().children {
either = append(either, child.children)
}
for _, cas := range either {
casMultiple := patternList{}
for _, e := range cas {
if cas.count(e) > 1 {
casMultiple = append(casMultiple, e)
}
}
for _, e := range casMultiple {
if e.t == patternArgument || e.t == patternOption && e.argcount > 0 {
switch e.value.(type) {
case string:
e.value = strings.Fields(e.value.(string))
case []string:
default:
e.value = []string{}
}
}
if e.t == patternCommand || e.t == patternOption && e.argcount == 0 {
e.value = 0
}
}
}
}
func (p *pattern) match(left *patternList, collected *patternList) (bool, *patternList, *patternList) {
if collected == nil {
collected = &patternList{}
}
if p.t&patternRequired != 0 {
l := left
c := collected
for _, p := range p.children {
var matched bool
matched, l, c = p.match(l, c)
if !matched {
return false, left, collected
}
}
return true, l, c
} else if p.t&patternOptionAL != 0 || p.t&patternOptionSSHORTCUT != 0 {
for _, p := range p.children {
_, left, collected = p.match(left, collected)
}
return true, left, collected
} else if p.t&patternOneOrMore != 0 {
if len(p.children) != 1 {
panic("OneOrMore.match(): assert len(p.children) == 1")
}
l := left
c := collected
var lAlt *patternList
matched := true
times := 0
for matched {
// could it be that something didn't match but changed l or c?
matched, l, c = p.children[0].match(l, c)
if matched {
times++
}
if lAlt == l {
break
}
lAlt = l
}
if times >= 1 {
return true, l, c
}
return false, left, collected
} else if p.t&patternEither != 0 {
type outcomeStruct struct {
matched bool
left *patternList
collected *patternList
length int
}
outcomes := []outcomeStruct{}
for _, p := range p.children {
matched, l, c := p.match(left, collected)
outcome := outcomeStruct{matched, l, c, len(*l)}
if matched {
outcomes = append(outcomes, outcome)
}
}
if len(outcomes) > 0 {
minLen := outcomes[0].length
minIndex := 0
for i, v := range outcomes {
if v.length < minLen {
minIndex = i
}
}
return outcomes[minIndex].matched, outcomes[minIndex].left, outcomes[minIndex].collected
}
return false, left, collected
} else if p.t&patternLeaf != 0 {
pos, match := p.singleMatch(left)
var increment interface{}
if match == nil {
return false, left, collected
}
leftAlt := make(patternList, len((*left)[:pos]), len((*left)[:pos])+len((*left)[pos+1:]))
copy(leftAlt, (*left)[:pos])
leftAlt = append(leftAlt, (*left)[pos+1:]...)
sameName := patternList{}
for _, a := range *collected {
if a.name == p.name {
sameName = append(sameName, a)
}
}
switch p.value.(type) {
case int, []string:
switch p.value.(type) {
case int:
increment = 1
case []string:
switch match.value.(type) {
case string:
increment = []string{match.value.(string)}
default:
increment = match.value
}
}
if len(sameName) == 0 {
match.value = increment
collectedMatch := make(patternList, len(*collected), len(*collected)+1)
copy(collectedMatch, *collected)
collectedMatch = append(collectedMatch, match)
return true, &leftAlt, &collectedMatch
}
switch sameName[0].value.(type) {
case int:
sameName[0].value = sameName[0].value.(int) + increment.(int)
case []string:
sameName[0].value = append(sameName[0].value.([]string), increment.([]string)...)
}
return true, &leftAlt, collected
}
collectedMatch := make(patternList, len(*collected), len(*collected)+1)
copy(collectedMatch, *collected)
collectedMatch = append(collectedMatch, match)
return true, &leftAlt, &collectedMatch
}
panic("unmatched type")
}
func (p *pattern) singleMatch(left *patternList) (int, *pattern) {
if p.t&patternArgument != 0 {
for n, pat := range *left {
if pat.t&patternArgument != 0 {
return n, newArgument(p.name, pat.value)
}
}
return -1, nil
} else if p.t&patternCommand != 0 {
for n, pat := range *left {
if pat.t&patternArgument != 0 {
if pat.value == p.name {
return n, newCommand(p.name, true)
}
break
}
}
return -1, nil
} else if p.t&patternOption != 0 {
for n, pat := range *left {
if p.name == pat.name {
return n, pat
}
}
return -1, nil
}
panic("unmatched type")
}
func (p *pattern) String() string {
if p.t&patternOption != 0 {
return fmt.Sprintf("%s(%s, %s, %d, %+v)", p.t, p.short, p.long, p.argcount, p.value)
} else if p.t&patternLeaf != 0 {
return fmt.Sprintf("%s(%s, %+v)", p.t, p.name, p.value)
} else if p.t&patternBranch != 0 {
result := ""
for i, child := range p.children {
if i > 0 {
result += ", "
}
result += child.String()
}
return fmt.Sprintf("%s(%s)", p.t, result)
}
panic("unmatched type")
}
func (p *pattern) transform() *pattern {
/*
Expand pattern into an (almost) equivalent one, but with single Either.
Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
Quirks: [-a] => (-a), (-a...) => (-a -a)
*/
result := []patternList{}
groups := []patternList{patternList{p}}
parents := patternRequired +
patternOptionAL +
patternOptionSSHORTCUT +
patternEither +
patternOneOrMore
for len(groups) > 0 {
children := groups[0]
groups = groups[1:]
var child *pattern
for _, c := range children {
if c.t&parents != 0 {
child = c
break
}
}
if child != nil {
children.remove(child)
if child.t&patternEither != 0 {
for _, c := range child.children {
r := patternList{}
r = append(r, c)
r = append(r, children...)
groups = append(groups, r)
}
} else if child.t&patternOneOrMore != 0 {
r := patternList{}
r = append(r, child.children.double()...)
r = append(r, children...)
groups = append(groups, r)
} else {
r := patternList{}
r = append(r, child.children...)
r = append(r, children...)
groups = append(groups, r)
}
} else {
result = append(result, children)
}
}
either := patternList{}
for _, e := range result {
either = append(either, newRequired(e...))
}
return newEither(either...)
}
func (p *pattern) eq(other *pattern) bool {
return reflect.DeepEqual(p, other)
}
func (pl patternList) unique() patternList {
table := make(map[string]bool)
result := patternList{}
for _, v := range pl {
if !table[v.String()] {
table[v.String()] = true
result = append(result, v)
}
}
return result
}
func (pl patternList) index(p *pattern) (int, error) {
for i, c := range pl {
if c.eq(p) {
return i, nil
}
}
return -1, newError("%s not in list", p)
}
func (pl patternList) count(p *pattern) int {
count := 0
for _, c := range pl {
if c.eq(p) {
count++
}
}
return count
}
func (pl patternList) diff(l patternList) patternList {
lAlt := make(patternList, len(l))
copy(lAlt, l)
result := make(patternList, 0, len(pl))
for _, v := range pl {
if v != nil {
match := false
for i, w := range lAlt {
if w.eq(v) {
match = true
lAlt[i] = nil
break
}
}
if match == false {
result = append(result, v)
}
}
}
return result
}
func (pl patternList) double() patternList {
l := len(pl)
result := make(patternList, l*2)
copy(result, pl)
copy(result[l:2*l], pl)
return result
}
func (pl *patternList) remove(p *pattern) {
(*pl) = pl.diff(patternList{p})
}
func (pl patternList) dictionary() map[string]interface{} {
dict := make(map[string]interface{})
for _, a := range pl {
dict[a.name] = a.value
}
return dict
}

View File

@ -0,0 +1,9 @@
r"""usage: prog [NAME_-2]..."""
$ prog 10 20
{"NAME_-2": ["10", "20"]}
$ prog 10
{"NAME_-2": ["10"]}
$ prog
{"NAME_-2": []}

957
vendor/github.com/docopt/docopt.go/testcases.docopt generated vendored Normal file
View File

@ -0,0 +1,957 @@
r"""Usage: prog
"""
$ prog
{}
$ prog --xxx
"user-error"
r"""Usage: prog [options]
Options: -a All.
"""
$ prog
{"-a": false}
$ prog -a
{"-a": true}
$ prog -x
"user-error"
r"""Usage: prog [options]
Options: --all All.
"""
$ prog
{"--all": false}
$ prog --all
{"--all": true}
$ prog --xxx
"user-error"
r"""Usage: prog [options]
Options: -v, --verbose Verbose.
"""
$ prog --verbose
{"--verbose": true}
$ prog --ver
{"--verbose": true}
$ prog -v
{"--verbose": true}
r"""Usage: prog [options]
Options: -p PATH
"""
$ prog -p home/
{"-p": "home/"}
$ prog -phome/
{"-p": "home/"}
$ prog -p
"user-error"
r"""Usage: prog [options]
Options: --path <path>
"""
$ prog --path home/
{"--path": "home/"}
$ prog --path=home/
{"--path": "home/"}
$ prog --pa home/
{"--path": "home/"}
$ prog --pa=home/
{"--path": "home/"}
$ prog --path
"user-error"
r"""Usage: prog [options]
Options: -p PATH, --path=<path> Path to files.
"""
$ prog -proot
{"--path": "root"}
r"""Usage: prog [options]
Options: -p --path PATH Path to files.
"""
$ prog -p root
{"--path": "root"}
$ prog --path root
{"--path": "root"}
r"""Usage: prog [options]
Options:
-p PATH Path to files [default: ./]
"""
$ prog
{"-p": "./"}
$ prog -phome
{"-p": "home"}
r"""UsAgE: prog [options]
OpTiOnS: --path=<files> Path to files
[dEfAuLt: /root]
"""
$ prog
{"--path": "/root"}
$ prog --path=home
{"--path": "home"}
r"""usage: prog [options]
options:
-a Add
-r Remote
-m <msg> Message
"""
$ prog -a -r -m Hello
{"-a": true,
"-r": true,
"-m": "Hello"}
$ prog -armyourass
{"-a": true,
"-r": true,
"-m": "yourass"}
$ prog -a -r
{"-a": true,
"-r": true,
"-m": null}
r"""Usage: prog [options]
Options: --version
--verbose
"""
$ prog --version
{"--version": true,
"--verbose": false}
$ prog --verbose
{"--version": false,
"--verbose": true}
$ prog --ver
"user-error"
$ prog --verb
{"--version": false,
"--verbose": true}
r"""usage: prog [-a -r -m <msg>]
options:
-a Add
-r Remote
-m <msg> Message
"""
$ prog -armyourass
{"-a": true,
"-r": true,
"-m": "yourass"}
r"""usage: prog [-armmsg]
options: -a Add
-r Remote
-m <msg> Message
"""
$ prog -a -r -m Hello
{"-a": true,
"-r": true,
"-m": "Hello"}
r"""usage: prog -a -b
options:
-a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog
"user-error"
r"""usage: prog (-a -b)
options: -a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog
"user-error"
r"""usage: prog [-a] -b
options: -a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog -b
{"-a": false, "-b": true}
$ prog
"user-error"
r"""usage: prog [(-a -b)]
options: -a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog -b
"user-error"
$ prog
{"-a": false, "-b": false}
r"""usage: prog (-a|-b)
options: -a
-b
"""
$ prog -a -b
"user-error"
$ prog
"user-error"
$ prog -a
{"-a": true, "-b": false}
$ prog -b
{"-a": false, "-b": true}
r"""usage: prog [ -a | -b ]
options: -a
-b
"""
$ prog -a -b
"user-error"
$ prog
{"-a": false, "-b": false}
$ prog -a
{"-a": true, "-b": false}
$ prog -b
{"-a": false, "-b": true}
r"""usage: prog <arg>"""
$ prog 10
{"<arg>": "10"}
$ prog 10 20
"user-error"
$ prog
"user-error"
r"""usage: prog [<arg>]"""
$ prog 10
{"<arg>": "10"}
$ prog 10 20
"user-error"
$ prog
{"<arg>": null}
r"""usage: prog <kind> <name> <type>"""
$ prog 10 20 40
{"<kind>": "10", "<name>": "20", "<type>": "40"}
$ prog 10 20
"user-error"
$ prog
"user-error"
r"""usage: prog <kind> [<name> <type>]"""
$ prog 10 20 40
{"<kind>": "10", "<name>": "20", "<type>": "40"}
$ prog 10 20
{"<kind>": "10", "<name>": "20", "<type>": null}
$ prog
"user-error"
r"""usage: prog [<kind> | <name> <type>]"""
$ prog 10 20 40
"user-error"
$ prog 20 40
{"<kind>": null, "<name>": "20", "<type>": "40"}
$ prog
{"<kind>": null, "<name>": null, "<type>": null}
r"""usage: prog (<kind> --all | <name>)
options:
--all
"""
$ prog 10 --all
{"<kind>": "10", "--all": true, "<name>": null}
$ prog 10
{"<kind>": null, "--all": false, "<name>": "10"}
$ prog
"user-error"
r"""usage: prog [<name> <name>]"""
$ prog 10 20
{"<name>": ["10", "20"]}
$ prog 10
{"<name>": ["10"]}
$ prog
{"<name>": []}
r"""usage: prog [(<name> <name>)]"""
$ prog 10 20
{"<name>": ["10", "20"]}
$ prog 10
"user-error"
$ prog
{"<name>": []}
r"""usage: prog NAME..."""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
"user-error"
r"""usage: prog [NAME]..."""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
{"NAME": []}
r"""usage: prog [NAME...]"""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
{"NAME": []}
r"""usage: prog [NAME [NAME ...]]"""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
{"NAME": []}
r"""usage: prog (NAME | --foo NAME)
options: --foo
"""
$ prog 10
{"NAME": "10", "--foo": false}
$ prog --foo 10
{"NAME": "10", "--foo": true}
$ prog --foo=10
"user-error"
r"""usage: prog (NAME | --foo) [--bar | NAME]
options: --foo
options: --bar
"""
$ prog 10
{"NAME": ["10"], "--foo": false, "--bar": false}
$ prog 10 20
{"NAME": ["10", "20"], "--foo": false, "--bar": false}
$ prog --foo --bar
{"NAME": [], "--foo": true, "--bar": true}
r"""Naval Fate.
Usage:
prog ship new <name>...
prog ship [<name>] move <x> <y> [--speed=<kn>]
prog ship shoot <x> <y>
prog mine (set|remove) <x> <y> [--moored|--drifting]
prog -h | --help
prog --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Mored (anchored) mine.
--drifting Drifting mine.
"""
$ prog ship Guardian move 150 300 --speed=20
{"--drifting": false,
"--help": false,
"--moored": false,
"--speed": "20",
"--version": false,
"<name>": ["Guardian"],
"<x>": "150",
"<y>": "300",
"mine": false,
"move": true,
"new": false,
"remove": false,
"set": false,
"ship": true,
"shoot": false}
r"""usage: prog --hello"""
$ prog --hello
{"--hello": true}
r"""usage: prog [--hello=<world>]"""
$ prog
{"--hello": null}
$ prog --hello wrld
{"--hello": "wrld"}
r"""usage: prog [-o]"""
$ prog
{"-o": false}
$ prog -o
{"-o": true}
r"""usage: prog [-opr]"""
$ prog -op
{"-o": true, "-p": true, "-r": false}
r"""usage: prog --aabb | --aa"""
$ prog --aa
{"--aabb": false, "--aa": true}
$ prog --a
"user-error" # not a unique prefix
#
# Counting number of flags
#
r"""Usage: prog -v"""
$ prog -v
{"-v": true}
r"""Usage: prog [-v -v]"""
$ prog
{"-v": 0}
$ prog -v
{"-v": 1}
$ prog -vv
{"-v": 2}
r"""Usage: prog -v ..."""
$ prog
"user-error"
$ prog -v
{"-v": 1}
$ prog -vv
{"-v": 2}
$ prog -vvvvvv
{"-v": 6}
r"""Usage: prog [-v | -vv | -vvv]
This one is probably most readable user-friednly variant.
"""
$ prog
{"-v": 0}
$ prog -v
{"-v": 1}
$ prog -vv
{"-v": 2}
$ prog -vvvv
"user-error"
r"""usage: prog [--ver --ver]"""
$ prog --ver --ver
{"--ver": 2}
#
# Counting commands
#
r"""usage: prog [go]"""
$ prog go
{"go": true}
r"""usage: prog [go go]"""
$ prog
{"go": 0}
$ prog go
{"go": 1}
$ prog go go
{"go": 2}
$ prog go go go
"user-error"
r"""usage: prog go..."""
$ prog go go go go go
{"go": 5}
#
# [options] does not include options from usage-pattern
#
r"""usage: prog [options] [-a]
options: -a
-b
"""
$ prog -a
{"-a": true, "-b": false}
$ prog -aa
"user-error"
#
# Test [options] shourtcut
#
r"""Usage: prog [options] A
Options:
-q Be quiet
-v Be verbose.
"""
$ prog arg
{"A": "arg", "-v": false, "-q": false}
$ prog -v arg
{"A": "arg", "-v": true, "-q": false}
$ prog -q arg
{"A": "arg", "-v": false, "-q": true}
#
# Test single dash
#
r"""usage: prog [-]"""
$ prog -
{"-": true}
$ prog
{"-": false}
#
# If argument is repeated, its value should always be a list
#
r"""usage: prog [NAME [NAME ...]]"""
$ prog a b
{"NAME": ["a", "b"]}
$ prog
{"NAME": []}
#
# Option's argument defaults to null/None
#
r"""usage: prog [options]
options:
-a Add
-m <msg> Message
"""
$ prog -a
{"-m": null, "-a": true}
#
# Test options without description
#
r"""usage: prog --hello"""
$ prog --hello
{"--hello": true}
r"""usage: prog [--hello=<world>]"""
$ prog
{"--hello": null}
$ prog --hello wrld
{"--hello": "wrld"}
r"""usage: prog [-o]"""
$ prog
{"-o": false}
$ prog -o
{"-o": true}
r"""usage: prog [-opr]"""
$ prog -op
{"-o": true, "-p": true, "-r": false}
r"""usage: git [-v | --verbose]"""
$ prog -v
{"-v": true, "--verbose": false}
r"""usage: git remote [-v | --verbose]"""
$ prog remote -v
{"remote": true, "-v": true, "--verbose": false}
#
# Test empty usage pattern
#
r"""usage: prog"""
$ prog
{}
r"""usage: prog
prog <a> <b>
"""
$ prog 1 2
{"<a>": "1", "<b>": "2"}
$ prog
{"<a>": null, "<b>": null}
r"""usage: prog <a> <b>
prog
"""
$ prog
{"<a>": null, "<b>": null}
#
# Option's argument should not capture default value from usage pattern
#
r"""usage: prog [--file=<f>]"""
$ prog
{"--file": null}
r"""usage: prog [--file=<f>]
options: --file <a>
"""
$ prog
{"--file": null}
r"""Usage: prog [-a <host:port>]
Options: -a, --address <host:port> TCP address [default: localhost:6283].
"""
$ prog
{"--address": "localhost:6283"}
#
# If option with argument could be repeated,
# its arguments should be accumulated into a list
#
r"""usage: prog --long=<arg> ..."""
$ prog --long one
{"--long": ["one"]}
$ prog --long one --long two
{"--long": ["one", "two"]}
#
# Test multiple elements repeated at once
#
r"""usage: prog (go <direction> --speed=<km/h>)..."""
$ prog go left --speed=5 go right --speed=9
{"go": 2, "<direction>": ["left", "right"], "--speed": ["5", "9"]}
#
# Required options should work with option shortcut
#
r"""usage: prog [options] -a
options: -a
"""
$ prog -a
{"-a": true}
#
# If option could be repeated its defaults should be split into a list
#
r"""usage: prog [-o <o>]...
options: -o <o> [default: x]
"""
$ prog -o this -o that
{"-o": ["this", "that"]}
$ prog
{"-o": ["x"]}
r"""usage: prog [-o <o>]...
options: -o <o> [default: x y]
"""
$ prog -o this
{"-o": ["this"]}
$ prog
{"-o": ["x", "y"]}
#
# Test stacked option's argument
#
r"""usage: prog -pPATH
options: -p PATH
"""
$ prog -pHOME
{"-p": "HOME"}
#
# Issue 56: Repeated mutually exclusive args give nested lists sometimes
#
r"""Usage: foo (--xx=x|--yy=y)..."""
$ prog --xx=1 --yy=2
{"--xx": ["1"], "--yy": ["2"]}
#
# POSIXly correct tokenization
#
r"""usage: prog [<input file>]"""
$ prog f.txt
{"<input file>": "f.txt"}
r"""usage: prog [--input=<file name>]..."""
$ prog --input a.txt --input=b.txt
{"--input": ["a.txt", "b.txt"]}
#
# Issue 85: `[options]` shourtcut with multiple subcommands
#
r"""usage: prog good [options]
prog fail [options]
options: --loglevel=N
"""
$ prog fail --loglevel 5
{"--loglevel": "5", "fail": true, "good": false}
#
# Usage-section syntax
#
r"""usage:prog --foo"""
$ prog --foo
{"--foo": true}
r"""PROGRAM USAGE: prog --foo"""
$ prog --foo
{"--foo": true}
r"""Usage: prog --foo
prog --bar
NOT PART OF SECTION"""
$ prog --foo
{"--foo": true, "--bar": false}
r"""Usage:
prog --foo
prog --bar
NOT PART OF SECTION"""
$ prog --foo
{"--foo": true, "--bar": false}
r"""Usage:
prog --foo
prog --bar
NOT PART OF SECTION"""
$ prog --foo
{"--foo": true, "--bar": false}
#
# Options-section syntax
#
r"""Usage: prog [options]
global options: --foo
local options: --baz
--bar
other options:
--egg
--spam
-not-an-option-
"""
$ prog --baz --egg
{"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}

126
vendor/github.com/docopt/docopt.go/token.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package docopt
import (
"regexp"
"strings"
"unicode"
)
type tokenList struct {
tokens []string
errorFunc func(string, ...interface{}) error
err errorType
}
type token string
func newTokenList(source []string, err errorType) *tokenList {
errorFunc := newError
if err == errorUser {
errorFunc = newUserError
} else if err == errorLanguage {
errorFunc = newLanguageError
}
return &tokenList{source, errorFunc, err}
}
func tokenListFromString(source string) *tokenList {
return newTokenList(strings.Fields(source), errorUser)
}
func tokenListFromPattern(source string) *tokenList {
p := regexp.MustCompile(`([\[\]\(\)\|]|\.\.\.)`)
source = p.ReplaceAllString(source, ` $1 `)
p = regexp.MustCompile(`\s+|(\S*<.*?>)`)
split := p.Split(source, -1)
match := p.FindAllStringSubmatch(source, -1)
var result []string
l := len(split)
for i := 0; i < l; i++ {
if len(split[i]) > 0 {
result = append(result, split[i])
}
if i < l-1 && len(match[i][1]) > 0 {
result = append(result, match[i][1])
}
}
return newTokenList(result, errorLanguage)
}
func (t *token) eq(s string) bool {
if t == nil {
return false
}
return string(*t) == s
}
func (t *token) match(matchNil bool, tokenStrings ...string) bool {
if t == nil && matchNil {
return true
} else if t == nil && !matchNil {
return false
}
for _, tok := range tokenStrings {
if tok == string(*t) {
return true
}
}
return false
}
func (t *token) hasPrefix(prefix string) bool {
if t == nil {
return false
}
return strings.HasPrefix(string(*t), prefix)
}
func (t *token) hasSuffix(suffix string) bool {
if t == nil {
return false
}
return strings.HasSuffix(string(*t), suffix)
}
func (t *token) isUpper() bool {
if t == nil {
return false
}
return isStringUppercase(string(*t))
}
func (t *token) String() string {
if t == nil {
return ""
}
return string(*t)
}
func (tl *tokenList) current() *token {
if len(tl.tokens) > 0 {
return (*token)(&(tl.tokens[0]))
}
return nil
}
func (tl *tokenList) length() int {
return len(tl.tokens)
}
func (tl *tokenList) move() *token {
if len(tl.tokens) > 0 {
t := tl.tokens[0]
tl.tokens = tl.tokens[1:]
return (*token)(&t)
}
return nil
}
// returns true if all cased characters in the string are uppercase
// and there are there is at least one cased charcter
func isStringUppercase(s string) bool {
if strings.ToUpper(s) != s {
return false
}
for _, c := range []rune(s) {
if unicode.IsUpper(c) {
return true
}
}
return false
}

28
vendor/github.com/gizak/termui/.gitignore generated vendored Normal file
View File

@ -0,0 +1,28 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
.DS_Store
/vendor
.vscode/
.mypy_cache/

36
vendor/github.com/gizak/termui/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,36 @@
Feel free to search/open an issue if something is missing or confusing from the changelog, since many things have been in flux.
## TODO
- moved widgets to `github.com/gizak/termui/widgets`
- rewrote widgets (check examples and code)
- rewrote grid
- grids are created locally instead of through `termui.Body`
- grids can be nested
- changed grid layout mechanism
- columns and rows can be arbitrarily nested
- column and row size is now specified as a ratio of the available space
- `Buffer` `Cell`s now contain an `AttrPair` which holds a `Fg` and `Bg`
- Change `Bufferer` interface to `Drawable`
- Add `GetRect` and `SetRect` methods to control widget sizing
- Change `Buffer` method to `Draw`
- `Draw` takes a `Buffer` and draws to it instead of creating a new one
- Created a global `Theme` struct which holds the default `Attributes` of everything
- Combined `TermWidth` and `TermHeight` functions into `TerminalSize`
- Added `Canvas` which allows for drawing braille lines to a `Buffer`
- Refactored `Block`
- Refactored `Buffer` methods
- Set `termbox-go` backend to 256 colors by default
## 18/11/29
- Move Tabpane from termui/extra to termui and rename it to TabPane
- Rename PollEvent to PollEvents
## 18/11/28
- Migrated from Dep to vgo
- Overhauled the event system
- check the wiki/examples for details
- Renamed Par widget to Paragraph
- Renamed MBarChart widget to StackedBarChart

22
vendor/github.com/gizak/termui/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Zack Guo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

5
vendor/github.com/gizak/termui/Makefile generated vendored Normal file
View File

@ -0,0 +1,5 @@
.PHONY: run-examples
run-examples:
@for file in _examples/*.go; do \
go run $$file; \
done;

84
vendor/github.com/gizak/termui/README.md generated vendored Normal file
View File

@ -0,0 +1,84 @@
# termui
<img src="./assets/dashboard1.gif" alt="demo cast under osx 10.10; Terminal.app; Menlo Regular 12pt.)" width="100%">
termui is a cross-platform, easy-to-compile, and fully-customizable terminal dashboard built on top of [termbox-go](https://github.com/nsf/termbox-go). It is inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib) and written purely in Go.
## Installation
Installing from the master branch is recommended:
```bash
go get -u github.com/gizak/termui@master
```
**Note**: termui is currently undergoing API changes so make sure to check the changelog when upgrading.
If you upgrade and notice something is missing or don't like a change, revert the upgrade and open an issue.
## Usage
### Hello World
```go
package main
import (
ui "github.com/gizak/termui"
"github.com/gizak/termui/widgets"
)
func main() {
if err := ui.Init(); err != nil {
panic(err)
}
defer ui.Close()
p := widgets.NewParagraph()
p.Text = "Hello World!"
p.SetRect(0, 0, 25, 5)
ui.Render(p)
for e := range ui.PollEvents() {
if e.Type == ui.KeyboardEvent {
break
}
}
}
```
### Widgets
Click image to see the corresponding demo codes.
[<img src="./assets/barchart.png" alt="barchart" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/barchart.go)
[<img src="./assets/gauge.png" alt="gauge" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/gauge.go)
[<img src="./assets/linechart.png" alt="linechart" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/linechart.go)
[<img src="./assets/list.png" alt="list" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/list.go)
[<img src="./assets/paragraph.png" alt="paragraph" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/paragraph.go)
[<img src="./assets/sparkline.png" alt="sparkline" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/sparkline.go)
[<img src="./assets/stacked_barchart.png" alt="stacked_barchart" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/stacked_barchart.go)
[<img src="./assets/table.png" alt="table" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_examples/table.go)
### Examples
Examples can be found in [\_examples](./_examples). Run an example with `go run _examples/{example}.go` or run all of them consecutively with `make run-examples`.
## Documentation
- [wiki](https://github.com/gizak/termui/wiki)
## Uses
- [cjbassi/gotop](https://github.com/cjbassi/gotop)
- [go-ethereum/monitorcmd](https://github.com/ethereum/go-ethereum/blob/96116758d22ddbff4dbef2050d6b63a7b74502d8/cmd/geth/monitorcmd.go)
## Related Works
- [blessed-contrib](https://github.com/yaronn/blessed-contrib)
- [tui-rs](https://github.com/fdehau/tui-rs)
- [gocui](https://github.com/jroimartin/gocui)
## License
[MIT](http://opensource.org/licenses/MIT)

9
vendor/github.com/gizak/termui/alignment.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
package termui
type Alignment int
const (
AlignLeft Alignment = iota
AlignCenter
AlignRight
)

31
vendor/github.com/gizak/termui/attributes.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
package termui
// Attribute is printable cell's color and style.
type Attribute int
// Define basic terminal colors
const (
// ColorDefault clears the color
ColorDefault Attribute = iota - 1
ColorBlack
ColorRed
ColorGreen
ColorYellow
ColorBlue
ColorMagenta
ColorCyan
ColorWhite
)
// These can be bitwise ored to modify cells
const (
AttrBold Attribute = 1 << (iota + 9)
AttrUnderline
AttrReverse
)
// AttrPair holds a cell's Fg and Bg
type AttrPair struct {
Fg Attribute
Bg Attribute
}

93
vendor/github.com/gizak/termui/block.go generated vendored Normal file
View File

@ -0,0 +1,93 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
"image"
)
type Block struct {
Border bool
BorderAttrs AttrPair
BorderLeft bool
BorderRight bool
BorderTop bool
BorderBottom bool
image.Rectangle
Inner image.Rectangle
Title string
TitleAttrs AttrPair
}
// NewBlock returns a *Block which inherits styles from current theme.
func NewBlock() *Block {
return &Block{
Border: true,
BorderAttrs: Theme.Block.Border,
BorderLeft: true,
BorderRight: true,
BorderTop: true,
BorderBottom: true,
TitleAttrs: Theme.Block.Title,
}
}
func (b *Block) drawBorder(buf *Buffer) {
if !b.Border {
return
}
verticalCell := Cell{VERTICAL_LINE, b.BorderAttrs}
horizontalCell := Cell{HORIZONTAL_LINE, b.BorderAttrs}
// draw lines
if b.BorderTop {
buf.Fill(horizontalCell, image.Rect(b.Min.X, b.Min.Y, b.Max.X, b.Min.Y+1))
}
if b.BorderBottom {
buf.Fill(horizontalCell, image.Rect(b.Min.X, b.Max.Y-1, b.Max.X, b.Max.Y))
}
if b.BorderLeft {
buf.Fill(verticalCell, image.Rect(b.Min.X, b.Min.Y, b.Min.X+1, b.Max.Y))
}
if b.BorderRight {
buf.Fill(verticalCell, image.Rect(b.Max.X-1, b.Min.Y, b.Max.X, b.Max.Y))
}
// draw corners
if b.BorderTop && b.BorderLeft {
buf.SetCell(Cell{TOP_LEFT, b.BorderAttrs}, b.Min)
}
if b.BorderTop && b.BorderRight {
buf.SetCell(Cell{TOP_RIGHT, b.BorderAttrs}, image.Pt(b.Max.X-1, b.Min.Y))
}
if b.BorderBottom && b.BorderLeft {
buf.SetCell(Cell{BOTTOM_LEFT, b.BorderAttrs}, image.Pt(b.Min.X, b.Max.Y-1))
}
if b.BorderBottom && b.BorderRight {
buf.SetCell(Cell{BOTTOM_RIGHT, b.BorderAttrs}, b.Max.Sub(image.Pt(1, 1)))
}
}
func (b *Block) Draw(buf *Buffer) {
b.drawBorder(buf)
buf.SetString(
b.Title,
b.TitleAttrs,
image.Pt(b.Min.X+2, b.Min.Y),
)
}
func (b *Block) SetRect(x1, y1, x2, y2 int) {
b.Rectangle = image.Rect(x1, y1, x2, y2)
b.Inner = image.Rect(b.Min.X+1, b.Min.Y+1, b.Max.X-1, b.Max.Y-1)
}
func (b *Block) GetRect() image.Rectangle {
return b.Rectangle
}

52
vendor/github.com/gizak/termui/buffer.go generated vendored Normal file
View File

@ -0,0 +1,52 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
"image"
)
// Cell represents a terminal cell and is a rune with Fg and Bg Attributes
type Cell struct {
Rune rune
Attrs AttrPair
}
// Buffer represents a section of a terminal and is a renderable rectangle cell data container.
type Buffer struct {
image.Rectangle
CellMap map[image.Point]Cell
}
func NewBuffer(r image.Rectangle) *Buffer {
buf := &Buffer{
Rectangle: r,
CellMap: make(map[image.Point]Cell),
}
buf.Fill(Cell{' ', AttrPair{ColorDefault, ColorDefault}}, r) // clears out area
return buf
}
func (b *Buffer) GetCell(p image.Point) Cell {
return b.CellMap[p]
}
func (b *Buffer) SetCell(c Cell, p image.Point) {
b.CellMap[p] = c
}
func (b *Buffer) Fill(c Cell, rect image.Rectangle) {
for x := rect.Min.X; x < rect.Max.X; x++ {
for y := rect.Min.Y; y < rect.Max.Y; y++ {
b.SetCell(c, image.Pt(x, y))
}
}
}
func (b *Buffer) SetString(s string, pair AttrPair, p image.Point) {
for i, char := range s {
b.SetCell(Cell{char, pair}, image.Pt(p.X+i, p.Y))
}
}

62
vendor/github.com/gizak/termui/canvas.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
package termui
import (
"image"
)
type Canvas struct {
CellMap map[image.Point]Cell
Block
}
func NewCanvas() *Canvas {
return &Canvas{
Block: *NewBlock(),
CellMap: make(map[image.Point]Cell),
}
}
// given points correspond to dots within a braille character, not cells
func (c *Canvas) Line(p0, p1 image.Point, attr Attribute) {
leftPoint, rightPoint := p0, p1
if leftPoint.X > rightPoint.X {
leftPoint, rightPoint = rightPoint, leftPoint
}
xDistance := AbsInt(leftPoint.X - rightPoint.X)
yDistance := AbsInt(leftPoint.Y - rightPoint.Y)
slope := float64(yDistance) / float64(xDistance)
slopeDirection := 1
if rightPoint.Y < leftPoint.Y {
slopeDirection = -1
}
targetYCoordinate := float64(leftPoint.Y)
currentYCoordinate := leftPoint.Y
for i := leftPoint.X; i < rightPoint.X; i++ {
targetYCoordinate += (slope * float64(slopeDirection))
if currentYCoordinate == int(targetYCoordinate) {
point := image.Pt(i/2, currentYCoordinate/4)
c.CellMap[point] = Cell{
c.CellMap[point].Rune | BRAILLE[currentYCoordinate%4][i%2],
AttrPair{attr, ColorDefault},
}
}
for currentYCoordinate != int(targetYCoordinate) {
point := image.Pt(i/2, currentYCoordinate/4)
c.CellMap[point] = Cell{
c.CellMap[point].Rune | BRAILLE[currentYCoordinate%4][i%2],
AttrPair{attr, ColorDefault},
}
currentYCoordinate += slopeDirection
}
}
}
func (c *Canvas) Draw(buf *Buffer) {
for point, cell := range c.CellMap {
if point.In(c.Rectangle) {
buf.SetCell(Cell{cell.Rune + BRAILLE_OFFSET, cell.Attrs}, point)
}
}
}

8
vendor/github.com/gizak/termui/doc.go generated vendored Normal file
View File

@ -0,0 +1,8 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
/*
Package termui is a library for creating terminal user interfaces (TUIs) using widgets.
*/
package termui

175
vendor/github.com/gizak/termui/events.go generated vendored Normal file
View File

@ -0,0 +1,175 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
"strconv"
tb "github.com/nsf/termbox-go"
)
/*
List of events:
mouse events:
<MouseLeft> <MouseRight> <MouseMiddle>
<MouseWheelUp> <MouseWheelDown>
keyboard events:
any uppercase or lowercase letter or a set of two letters like j or jj or J or JJ
<C-d> etc
<M-d> etc
<Up> <Down> <Left> <Right>
<Insert> <Delete> <Home> <End> <Previous> <Next>
<Backspace> <Tab> <Enter> <Escape> <Space>
<C-<Space>> etc
terminal events:
<Resize>
*/
type EventType int
const (
KeyboardEvent EventType = iota
MouseEvent
ResizeEvent
)
type Event struct {
Type EventType
ID string
Payload interface{}
}
// Mouse payload.
type Mouse struct {
Drag bool
X int
Y int
}
// Resize payload.
type Resize struct {
Width int
Height int
}
// PollEvents gets events from termbox, converts them, then sends them to each of its channels.
func PollEvents() <-chan Event {
ch := make(chan Event)
go func() {
for {
ch <- convertTermboxEvent(tb.PollEvent())
}
}()
return ch
}
// convertTermboxKeyboardEvent converts a termbox keyboard event to a more friendly string format.
// Combines modifiers into the string instead of having them as additional fields in an event.
func convertTermboxKeyboardEvent(e tb.Event) Event {
k := string(e.Ch)
pre := ""
mod := ""
if e.Mod == tb.ModAlt {
mod = "<M-"
}
if e.Ch == 0 {
if e.Key > 0xFFFF-12 {
k = "<f" + strconv.Itoa(0xFFFF-int(e.Key)+1) + ">"
} else if e.Key > 0xFFFF-25 {
ks := []string{"<Insert>", "<Delete>", "<Home>", "<End>", "<Previous>", "<Next>", "<Up>", "<Down>", "<Left>", "<Right>"}
k = ks[0xFFFF-int(e.Key)-12]
}
if e.Key <= 0x7F {
pre = "<C-"
k = string('a' - 1 + int(e.Key))
kmap := map[tb.Key][2]string{
tb.KeyCtrlSpace: {"C-", "<Space>"},
tb.KeyBackspace: {"", "<Backspace>"},
tb.KeyTab: {"", "<Tab>"},
tb.KeyEnter: {"", "<Enter>"},
tb.KeyEsc: {"", "<Escape>"},
tb.KeyCtrlBackslash: {"C-", "\\"},
tb.KeyCtrlSlash: {"C-", "/"},
tb.KeySpace: {"", "<Space>"},
tb.KeyCtrl8: {"C-", "8"},
}
if sk, ok := kmap[e.Key]; ok {
pre = sk[0]
k = sk[1]
}
}
}
if pre != "" {
k += ">"
}
id := pre + mod + k
return Event{
Type: KeyboardEvent,
ID: id,
}
}
func convertTermboxMouseEvent(e tb.Event) Event {
mouseButtonMap := map[tb.Key]string{
tb.MouseLeft: "<MouseLeft>",
tb.MouseMiddle: "<MouseMiddle>",
tb.MouseRight: "<MouseRight>",
tb.MouseRelease: "<MouseRelease>",
tb.MouseWheelUp: "<MouseWheelUp>",
tb.MouseWheelDown: "<MouseWheelDown>",
}
converted, ok := mouseButtonMap[e.Key]
if !ok {
converted = "Unknown_Mouse_Button"
}
Drag := false
if e.Mod == tb.ModMotion {
Drag = true
}
return Event{
Type: MouseEvent,
ID: converted,
Payload: Mouse{
X: e.MouseX,
Y: e.MouseY,
Drag: Drag,
},
}
}
// convertTermboxEvent turns a termbox event into a termui event.
func convertTermboxEvent(e tb.Event) Event {
if e.Type == tb.EventError {
panic(e.Err)
}
var event Event
switch e.Type {
case tb.EventKey:
event = convertTermboxKeyboardEvent(e)
case tb.EventMouse:
event = convertTermboxMouseEvent(e)
case tb.EventResize:
event = Event{
Type: ResizeEvent,
ID: "<Resize>",
Payload: Resize{
Width: e.Width,
Height: e.Height,
},
}
}
return event
}

7
vendor/github.com/gizak/termui/go.mod generated vendored Normal file
View File

@ -0,0 +1,7 @@
module github.com/gizak/termui
require (
github.com/mattn/go-runewidth v0.0.2
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7
github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb
)

6
vendor/github.com/gizak/termui/go.sum generated vendored Normal file
View File

@ -0,0 +1,6 @@
github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb h1:YahEjAGkJtCrkqgVHhX6n8ZX+CZ3hDRL9fjLYugLfSs=
github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=

156
vendor/github.com/gizak/termui/grid.go generated vendored Normal file
View File

@ -0,0 +1,156 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
type gridItemType int
const (
col gridItemType = 0
row gridItemType = 1
)
type Grid struct {
Block
Items []*GridItem
}
// GridItem represents either a Row or Column in a grid and holds sizing information and other GridItems or widgets
type GridItem struct {
Type gridItemType
XRatio float64
YRatio float64
WidthRatio float64
HeightRatio float64
Entry interface{} // Entry.type == GridBufferer if IsLeaf else []GridItem
IsLeaf bool
ratio float64
}
func NewGrid() *Grid {
g := &Grid{
Block: *NewBlock(),
}
g.Border = false
return g
}
// NewCol takes a height percentage and either a widget or a Row or Column
func NewCol(ratio float64, i ...interface{}) GridItem {
_, ok := i[0].(Drawable)
entry := i[0]
if !ok {
entry = i
}
return GridItem{
Type: col,
Entry: entry,
IsLeaf: ok,
ratio: ratio,
}
}
// NewRow takes a width percentage and either a widget or a Row or Column
func NewRow(ratio float64, i ...interface{}) GridItem {
_, ok := i[0].(Drawable)
entry := i[0]
if !ok {
entry = i
}
return GridItem{
Type: row,
Entry: entry,
IsLeaf: ok,
ratio: ratio,
}
}
// Set recursively searches the GridItems, adding leaves to the grid and calculating the dimensions of the leaves.
func (g *Grid) Set(entries ...interface{}) {
entry := GridItem{
Type: row,
Entry: entries,
IsLeaf: false,
ratio: 1.0,
}
g.setHelper(entry, 1.0, 1.0)
}
func (g *Grid) setHelper(item GridItem, parentWidthRatio, parentHeightRatio float64) {
var HeightRatio float64
var WidthRatio float64
switch item.Type {
case col:
HeightRatio = 1.0
WidthRatio = item.ratio
case row:
HeightRatio = item.ratio
WidthRatio = 1.0
}
item.WidthRatio = parentWidthRatio * WidthRatio
item.HeightRatio = parentHeightRatio * HeightRatio
if item.IsLeaf {
g.Items = append(g.Items, &item)
} else {
XRatio := 0.0
YRatio := 0.0
cols := false
rows := false
children := InterfaceSlice(item.Entry)
for i := 0; i < len(children); i++ {
if children[i] == nil {
continue
}
child, _ := children[i].(GridItem)
child.XRatio = item.XRatio + (item.WidthRatio * XRatio)
child.YRatio = item.YRatio + (item.HeightRatio * YRatio)
switch child.Type {
case col:
cols = true
XRatio += child.ratio
if rows {
item.HeightRatio /= 2
}
case row:
rows = true
YRatio += child.ratio
if cols {
item.WidthRatio /= 2
}
}
g.setHelper(child, item.WidthRatio, item.HeightRatio)
}
}
}
func (g *Grid) Draw(buf *Buffer) {
width := float64(g.Dx()) + 1
height := float64(g.Dy()) + 1
for _, item := range g.Items {
entry, _ := item.Entry.(Drawable)
x := int(width*item.XRatio) + g.Min.X
y := int(height*item.YRatio) + g.Min.Y
w := int(width * item.WidthRatio)
h := int(height * item.HeightRatio)
if x+w > g.Dx() {
w--
}
if y+h > g.Dy() {
h--
}
entry.SetRect(x, y, x+w, y+h)
entry.Draw(buf)
}
}

33
vendor/github.com/gizak/termui/init.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
tb "github.com/nsf/termbox-go"
)
// Init initializes termui library. This function should be called before any others.
// After initialization, the library must be finalized by 'Close' function.
func Init() error {
if err := tb.Init(); err != nil {
return err
}
tb.SetInputMode(tb.InputEsc | tb.InputMouse)
tb.SetOutputMode(tb.Output256)
return nil
}
// Close finalizes termui library.
// It should be called after successful initialization when termui's functionality isn't required anymore.
func Close() {
tb.Close()
}
func TerminalSize() (int, int) {
tb.Sync()
width, height := tb.Size()
return width, height
}

38
vendor/github.com/gizak/termui/render.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
"image"
tb "github.com/nsf/termbox-go"
)
type Drawable interface {
GetRect() image.Rectangle
SetRect(int, int, int, int)
Draw(*Buffer)
}
func Render(items ...Drawable) {
for _, item := range items {
buf := NewBuffer(item.GetRect())
item.Draw(buf)
for point, cell := range buf.CellMap {
if point.In(buf.Rectangle) {
tb.SetCell(
point.X, point.Y,
cell.Rune,
tb.Attribute(cell.Attrs.Fg)+1, tb.Attribute(cell.Attrs.Bg)+1,
)
}
}
}
tb.Flush()
}
func Clear() {
tb.Clear(tb.ColorDefault, tb.Attribute(Theme.Default.Bg+1))
}

44
vendor/github.com/gizak/termui/symbols.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
package termui
const (
SOLID_BLOCK = '░'
DOT = '•'
DOTS = '…'
)
var (
SPARK_CHARS = []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
BRAILLE_OFFSET = '\u2800'
BRAILLE = [4][2]rune{
{'\u0001', '\u0008'},
{'\u0002', '\u0010'},
{'\u0004', '\u0020'},
{'\u0040', '\u0080'},
}
DOUBLE_BRAILLE = map[[2]int]rune{
[2]int{0, 0}: '⣀',
[2]int{0, 1}: '⡠',
[2]int{0, 2}: '⡐',
[2]int{0, 3}: '⡈',
[2]int{1, 0}: '⢄',
[2]int{1, 1}: '⠤',
[2]int{1, 2}: '⠔',
[2]int{1, 3}: '⠌',
[2]int{2, 0}: '⢂',
[2]int{2, 1}: '⠢',
[2]int{2, 2}: '⠒',
[2]int{2, 3}: '⠊',
[2]int{3, 0}: '⢁',
[2]int{3, 1}: '⠡',
[2]int{3, 2}: '⠑',
[2]int{3, 3}: '⠉',
}
SINGLE_BRAILLE_LEFT = [4]rune{'\u2840', '⠄', '⠂', '⠁'}
SINGLE_BRAILLE_RIGHT = [4]rune{'\u2880', '⠠', '⠐', '⠈'}
)

28
vendor/github.com/gizak/termui/symbols_other.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
// +build !windows
package termui
const (
TOP_LEFT = '┌'
TOP_RIGHT = '┐'
BOTTOM_LEFT = '└'
BOTTOM_RIGHT = '┘'
VERTICAL_LINE = '│'
HORIZONTAL_LINE = '─'
VERTICAL_LEFT = '┤'
VERTICAL_RIGHT = '├'
HORIZONTAL_UP = '┴'
HORIZONTAL_DOWN = '┬'
QUOTA_LEFT = '«'
QUOTA_RIGHT = '»'
VERTICAL_DASH = '┊'
HORIZONTAL_DASH = '┈'
)

28
vendor/github.com/gizak/termui/symbols_windows.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
// +build windows
package termui
const (
TOP_LEFT = '+'
TOP_RIGHT = '+'
BOTTOM_LEFT = '+'
BOTTOM_RIGHT = '+'
VERTICAL_LINE = '|'
HORIZONTAL_LINE = '-'
VERTICAL_LEFT = '+'
VERTICAL_RIGHT = '+'
HORIZONTAL_UP = '+'
HORIZONTAL_DOWN = '+'
QUOTA_LEFT = '<'
QUOTA_RIGHT = '>'
VERTICAL_DASH = '|'
HORIZONTAL_DASH = '-'
)

256
vendor/github.com/gizak/termui/text_parser.go generated vendored Normal file
View File

@ -0,0 +1,256 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
"strings"
wordwrap "github.com/mitchellh/go-wordwrap"
)
type textParser struct {
baseAttrs AttrPair
plainTx []rune
markers []marker
}
type marker struct {
st int
ed int
fg Attribute
bg Attribute
}
var colorMap = map[string]Attribute{
"red": ColorRed,
"blue": ColorBlue,
"black": ColorBlack,
"cyan": ColorCyan,
"yellow": ColorYellow,
"white": ColorWhite,
"default": ColorDefault,
"green": ColorGreen,
"magenta": ColorMagenta,
}
var attributeMap = map[string]Attribute{
"bold": AttrBold,
"underline": AttrUnderline,
"reverse": AttrReverse,
}
// AddColorMap allows users to add/override the string to attribute mapping
func AddColorMap(str string, attr Attribute) {
colorMap[str] = attr
}
// readAttributes translates strings like `fg-red,fg-bold,bg-white` to fg and bg Attribute
func (tp *textParser) readAttributes(s string) (Attribute, Attribute) {
fg := tp.baseAttrs.Fg
bg := tp.baseAttrs.Bg
updateAttr := func(a Attribute, attrs []string) Attribute {
for _, s := range attrs {
// replace the color
if c, ok := colorMap[s]; ok {
a &= 0xFF00 // erase clr 0 ~ 8 bits
a |= c // set clr
}
// add attrs
if c, ok := attributeMap[s]; ok {
a |= c
}
}
return a
}
ss := strings.Split(s, ",")
fgs := []string{}
bgs := []string{}
for _, v := range ss {
subs := strings.Split(v, "-")
if len(subs) > 1 {
if subs[0] == "fg" {
fgs = append(fgs, subs[1])
} else if subs[0] == "bg" {
bgs = append(bgs, subs[1])
}
// else maybe error somehow?
}
}
fg = updateAttr(fg, fgs)
bg = updateAttr(bg, bgs)
return fg, bg
}
// parse streams and parses text into normalized text and render sequence.
func (tp *textParser) parse(str string) {
rs := []rune(str)
normTx := []rune{}
square := []rune{}
brackt := []rune{}
accSquare := false
accBrackt := false
cntSquare := 0
reset := func() {
square = []rune{}
brackt = []rune{}
accSquare = false
accBrackt = false
cntSquare = 0
}
// pipe stacks into normTx and clear
rollback := func() {
normTx = append(normTx, square...)
normTx = append(normTx, brackt...)
reset()
}
// chop first and last
chop := func(s []rune) []rune {
return s[1 : len(s)-1]
}
for i, r := range rs {
switch {
// stacking brackt
case accBrackt:
brackt = append(brackt, r)
if ')' == r {
fg, bg := tp.readAttributes(string(chop(brackt)))
st := len(normTx)
ed := len(normTx) + len(square) - 2
tp.markers = append(tp.markers, marker{st, ed, fg, bg})
normTx = append(normTx, chop(square)...)
reset()
} else if i+1 == len(rs) {
rollback()
}
// stacking square
case accSquare:
switch {
// squares closed and followed by a '('
case cntSquare == 0 && '(' == r:
accBrackt = true
brackt = append(brackt, '(')
// squares closed but not followed by a '('
case cntSquare == 0:
rollback()
if '[' == r {
accSquare = true
cntSquare = 1
brackt = append(brackt, '[')
} else {
normTx = append(normTx, r)
}
// hit the end
case i+1 == len(rs):
square = append(square, r)
rollback()
case '[' == r:
cntSquare++
square = append(square, '[')
case ']' == r:
cntSquare--
square = append(square, ']')
// normal char
default:
square = append(square, r)
}
// stacking normTx
default:
if '[' == r {
accSquare = true
cntSquare = 1
square = append(square, '[')
} else {
normTx = append(normTx, r)
}
}
}
tp.plainTx = normTx
}
func WrapText(cs []Cell, wl int) []Cell {
tmpCell := make([]Cell, len(cs))
copy(tmpCell, cs)
// get the plaintext
plain := CellsToString(cs)
// wrap
plainWrapped := wordwrap.WrapString(plain, uint(wl))
// find differences and insert
finalCell := tmpCell // finalcell will get the inserts and is what is returned
plainRune := []rune(plain)
plainWrappedRune := []rune(plainWrapped)
trigger := "go"
plainRuneNew := plainRune
for trigger != "stop" {
plainRune = plainRuneNew
for i := range plainRune {
if plainRune[i] == plainWrappedRune[i] {
trigger = "stop"
} else if plainRune[i] != plainWrappedRune[i] && plainWrappedRune[i] == 10 {
trigger = "go"
cell := Cell{10, AttrPair{0, 0}}
j := i - 0
// insert a cell into the []Cell in correct position
tmpCell[i] = cell
// insert the newline into plain so we avoid indexing errors
plainRuneNew = append(plainRune, 10)
copy(plainRuneNew[j+1:], plainRuneNew[j:])
plainRuneNew[j] = plainWrappedRune[j]
// restart the inner for loop until plain and plain wrapped are
// the same; yeah, it's inefficient, but the text amounts
// should be small
break
} else if plainRune[i] != plainWrappedRune[i] &&
plainWrappedRune[i-1] == 10 && // if the prior rune is a newline
plainRune[i] == 32 { // and this rune is a space
trigger = "go"
// need to delete plainRune[i] because it gets rid of an extra
// space
plainRuneNew = append(plainRune[:i], plainRune[i+1:]...)
break
} else {
trigger = "stop" // stops the outer for loop
}
}
}
finalCell = tmpCell
return finalCell
}
func ParseText(s string, baseAttrs AttrPair) []Cell {
tp := textParser{
baseAttrs: baseAttrs,
}
tp.parse(s)
cs := make([]Cell, len(tp.plainTx))
for i := range cs {
cs[i] = Cell{tp.plainTx[i], baseAttrs}
}
for _, mrk := range tp.markers {
for i := mrk.st; i < mrk.ed; i++ {
cs[i].Attrs.Fg = mrk.fg
cs[i].Attrs.Bg = mrk.bg
}
}
return cs
}

145
vendor/github.com/gizak/termui/theme.go generated vendored Normal file
View File

@ -0,0 +1,145 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
var StandardColors = []Attribute{
ColorRed,
ColorGreen,
ColorYellow,
ColorBlue,
ColorMagenta,
ColorCyan,
ColorWhite,
}
type RootTheme struct {
Default AttrPair
Block BlockTheme
BarChart BarChartTheme
Gauge GaugeTheme
LineChart LineChartTheme
List ListTheme
Paragraph ParagraphTheme
PieChart PieChartTheme
Sparkline SparklineTheme
StackedBarChart StackedBarChartTheme
Tab TabTheme
Table TableTheme
}
type BlockTheme struct {
Title AttrPair
Border AttrPair
}
type BarChartTheme struct {
Bars []Attribute
Nums []Attribute
Labels []Attribute
}
type GaugeTheme struct {
Percent Attribute
Bar Attribute
}
type LineChartTheme struct {
Lines []Attribute
Axes Attribute
}
type ListTheme struct {
Text AttrPair
}
type ParagraphTheme struct {
Text AttrPair
}
type PieChartTheme struct {
Slices []Attribute
}
type SparklineTheme struct {
Title AttrPair
Line Attribute
}
type StackedBarChartTheme struct {
Bars []Attribute
Nums []Attribute
Labels []Attribute
}
type TabTheme struct {
Active AttrPair
Inactive AttrPair
}
type TableTheme struct {
Text AttrPair
}
var Theme = RootTheme{
Default: AttrPair{7, -1},
Block: BlockTheme{
Title: AttrPair{7, -1},
Border: AttrPair{6, -1},
},
BarChart: BarChartTheme{
Bars: StandardColors,
Nums: StandardColors,
Labels: StandardColors,
},
Paragraph: ParagraphTheme{
Text: AttrPair{ColorWhite, -1},
},
PieChart: PieChartTheme{
Slices: StandardColors,
},
List: ListTheme{
Text: AttrPair{1, -1},
},
StackedBarChart: StackedBarChartTheme{
Bars: StandardColors,
Nums: StandardColors,
Labels: StandardColors,
},
Gauge: GaugeTheme{
Percent: ColorWhite,
Bar: ColorWhite,
},
Sparkline: SparklineTheme{
Line: ColorBlack,
Title: AttrPair{
Fg: ColorBlue,
Bg: ColorDefault,
},
},
LineChart: LineChartTheme{
Lines: StandardColors,
Axes: ColorBlue,
},
Table: TableTheme{
Text: AttrPair{4, -1},
},
Tab: TabTheme{
Active: AttrPair{ColorRed, ColorDefault},
Inactive: AttrPair{ColorWhite, ColorDefault},
},
}

127
vendor/github.com/gizak/termui/utils.go generated vendored Normal file
View File

@ -0,0 +1,127 @@
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
"fmt"
"math"
"reflect"
rw "github.com/mattn/go-runewidth"
)
// https://stackoverflow.com/questions/12753805/type-converting-slices-of-interfaces-in-go
func InterfaceSlice(slice interface{}) []interface{} {
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
panic("InterfaceSlice() given a non-slice type")
}
ret := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}
return ret
}
func MaxInt(x, y int) int {
if x > y {
return x
}
return y
}
func MinInt(x, y int) int {
if x < y {
return x
}
return y
}
func TrimString(s string, w int) string {
if w <= 0 {
return ""
}
if rw.StringWidth(s) > w {
return rw.Truncate(s, w, string(DOTS))
}
return s
}
func GetMaxIntFromSlice(slice []int) (int, error) {
if len(slice) == 0 {
return 0, fmt.Errorf("cannot get max value from empty slice")
}
var max int
for _, val := range slice {
if val > max {
max = val
}
}
return max, nil
}
func GetMaxFloat64From2dSlice(slices [][]float64) (float64, error) {
if len(slices) == 0 {
return 0, fmt.Errorf("cannot get max value from empty slice")
}
var max float64
for _, slice := range slices {
for _, val := range slice {
if val > max {
max = val
}
}
}
return max, nil
}
func SumIntSlice(slice []int) int {
sum := 0
for _, val := range slice {
sum += val
}
return sum
}
func SelectAttr(attrs []Attribute, index int) Attribute {
return attrs[index%len(attrs)]
}
func CellsToString(cells []Cell) string {
runes := make([]rune, len(cells))
for i, cell := range cells {
runes[i] = cell.Rune
}
return string(runes)
}
func RoundFloat64(x float64) float64 {
return math.Floor(x + 0.5)
}
func SumSliceFloat64(data []float64) float64 {
sum := 0.0
for _, v := range data {
sum += v
}
return sum
}
func AbsInt(x int) int {
if x >= 0 {
return x
}
return -x
}
func MinFloat64(x, y float64) float64 {
if x < y {
return x
}
return y
}

9
vendor/github.com/go-ole/go-ole/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
sudo: false
go:
- 1.1
- 1.2
- 1.3
- 1.4
- tip

49
vendor/github.com/go-ole/go-ole/ChangeLog.md generated vendored Normal file
View File

@ -0,0 +1,49 @@
# Version 1.x.x
* **Add more test cases and reference new test COM server project.** (Placeholder for future additions)
# Version 1.2.0-alphaX
**Minimum supported version is now Go 1.4. Go 1.1 support is deprecated, but should still build.**
* Added CI configuration for Travis-CI and AppVeyor.
* Added test InterfaceID and ClassID for the COM Test Server project.
* Added more inline documentation (#83).
* Added IEnumVARIANT implementation (#88).
* Added IEnumVARIANT test cases (#99, #100, #101).
* Added support for retrieving `time.Time` from VARIANT (#92).
* Added test case for IUnknown (#64).
* Added test case for IDispatch (#64).
* Added test cases for scalar variants (#64, #76).
# Version 1.1.1
* Fixes for Linux build.
* Fixes for Windows build.
# Version 1.1.0
The change to provide building on all platforms is a new feature. The increase in minor version reflects that and allows those who wish to stay on 1.0.x to continue to do so. Support for 1.0.x will be limited to bug fixes.
* Move GUID out of variables.go into its own file to make new documentation available.
* Move OleError out of ole.go into its own file to make new documentation available.
* Add documentation to utility functions.
* Add documentation to variant receiver functions.
* Add documentation to ole structures.
* Make variant available to other systems outside of Windows.
* Make OLE structures available to other systems outside of Windows.
## New Features
* Library should now be built on all platforms supported by Go. Library will NOOP on any platform that is not Windows.
* More functions are now documented and available on godoc.org.
# Version 1.0.1
1. Fix package references from repository location change.
# Version 1.0.0
This version is stable enough for use. The COM API is still incomplete, but provides enough functionality for accessing COM servers using IDispatch interface.
There is no changelog for this version. Check commits for history.

21
vendor/github.com/go-ole/go-ole/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2013-2017 Yasuhiro Matsumoto, <mattn.jp@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

46
vendor/github.com/go-ole/go-ole/README.md generated vendored Normal file
View File

@ -0,0 +1,46 @@
#Go OLE
[![Build status](https://ci.appveyor.com/api/projects/status/qr0u2sf7q43us9fj?svg=true)](https://ci.appveyor.com/project/jacobsantos/go-ole-jgs28)
[![Build Status](https://travis-ci.org/go-ole/go-ole.svg?branch=master)](https://travis-ci.org/go-ole/go-ole)
[![GoDoc](https://godoc.org/github.com/go-ole/go-ole?status.svg)](https://godoc.org/github.com/go-ole/go-ole)
Go bindings for Windows COM using shared libraries instead of cgo.
By Yasuhiro Matsumoto.
## Install
To experiment with go-ole, you can just compile and run the example program:
```
go get github.com/go-ole/go-ole
cd /path/to/go-ole/
go test
cd /path/to/go-ole/example/excel
go run excel.go
```
## Continuous Integration
Continuous integration configuration has been added for both Travis-CI and AppVeyor. You will have to add these to your own account for your fork in order for it to run.
**Travis-CI**
Travis-CI was added to check builds on Linux to ensure that `go get` works when cross building. Currently, Travis-CI is not used to test cross-building, but this may be changed in the future. It is also not currently possible to test the library on Linux, since COM API is specific to Windows and it is not currently possible to run a COM server on Linux or even connect to a remote COM server.
**AppVeyor**
AppVeyor is used to build on Windows using the (in-development) test COM server. It is currently only used to test the build and ensure that the code works on Windows. It will be used to register a COM server and then run the test cases based on the test COM server.
The tests currently do run and do pass and this should be maintained with commits.
##Versioning
Go OLE uses [semantic versioning](http://semver.org) for version numbers, which is similar to the version contract of the Go language. Which means that the major version will always maintain backwards compatibility with minor versions. Minor versions will only add new additions and changes. Fixes will always be in patch.
This contract should allow you to upgrade to new minor and patch versions without breakage or modifications to your existing code. Leave a ticket, if there is breakage, so that it could be fixed.
##LICENSE
Under the MIT License: http://mattn.mit-license.org/2013

54
vendor/github.com/go-ole/go-ole/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,54 @@
# Notes:
# - Minimal appveyor.yml file is an empty file. All sections are optional.
# - Indent each level of configuration with 2 spaces. Do not use tabs!
# - All section names are case-sensitive.
# - Section names should be unique on each level.
version: "1.3.0.{build}-alpha-{branch}"
os: Windows Server 2012 R2
branches:
only:
- master
- v1.2
- v1.1
- v1.0
skip_tags: true
clone_folder: c:\gopath\src\github.com\go-ole\go-ole
environment:
GOPATH: c:\gopath
matrix:
- GOARCH: amd64
GOVERSION: 1.5
GOROOT: c:\go
DOWNLOADPLATFORM: "x64"
install:
- choco install mingw
- SET PATH=c:\tools\mingw64\bin;%PATH%
# - Download COM Server
- ps: Start-FileDownload "https://github.com/go-ole/test-com-server/releases/download/v1.0.2/test-com-server-${env:DOWNLOADPLATFORM}.zip"
- 7z e test-com-server-%DOWNLOADPLATFORM%.zip -oc:\gopath\src\github.com\go-ole\go-ole > NUL
- c:\gopath\src\github.com\go-ole\go-ole\build\register-assembly.bat
# - set
- go version
- go env
- go get -u golang.org/x/tools/cmd/cover
- go get -u golang.org/x/tools/cmd/godoc
- go get -u golang.org/x/tools/cmd/stringer
build_script:
- cd c:\gopath\src\github.com\go-ole\go-ole
- go get -v -t ./...
- go build
- go test -v -cover ./...
# disable automatic tests
test: off
# disable deployment
deploy: off

329
vendor/github.com/go-ole/go-ole/com.go generated vendored Normal file
View File

@ -0,0 +1,329 @@
// +build windows
package ole
import (
"errors"
"syscall"
"time"
"unicode/utf16"
"unsafe"
)
var (
procCoInitialize, _ = modole32.FindProc("CoInitialize")
procCoInitializeEx, _ = modole32.FindProc("CoInitializeEx")
procCoUninitialize, _ = modole32.FindProc("CoUninitialize")
procCoCreateInstance, _ = modole32.FindProc("CoCreateInstance")
procCoTaskMemFree, _ = modole32.FindProc("CoTaskMemFree")
procCLSIDFromProgID, _ = modole32.FindProc("CLSIDFromProgID")
procCLSIDFromString, _ = modole32.FindProc("CLSIDFromString")
procStringFromCLSID, _ = modole32.FindProc("StringFromCLSID")
procStringFromIID, _ = modole32.FindProc("StringFromIID")
procIIDFromString, _ = modole32.FindProc("IIDFromString")
procGetUserDefaultLCID, _ = modkernel32.FindProc("GetUserDefaultLCID")
procCopyMemory, _ = modkernel32.FindProc("RtlMoveMemory")
procVariantInit, _ = modoleaut32.FindProc("VariantInit")
procVariantClear, _ = modoleaut32.FindProc("VariantClear")
procVariantTimeToSystemTime, _ = modoleaut32.FindProc("VariantTimeToSystemTime")
procSysAllocString, _ = modoleaut32.FindProc("SysAllocString")
procSysAllocStringLen, _ = modoleaut32.FindProc("SysAllocStringLen")
procSysFreeString, _ = modoleaut32.FindProc("SysFreeString")
procSysStringLen, _ = modoleaut32.FindProc("SysStringLen")
procCreateDispTypeInfo, _ = modoleaut32.FindProc("CreateDispTypeInfo")
procCreateStdDispatch, _ = modoleaut32.FindProc("CreateStdDispatch")
procGetActiveObject, _ = modoleaut32.FindProc("GetActiveObject")
procGetMessageW, _ = moduser32.FindProc("GetMessageW")
procDispatchMessageW, _ = moduser32.FindProc("DispatchMessageW")
)
// coInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func coInitialize() (err error) {
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms678543(v=vs.85).aspx
// Suggests that no value should be passed to CoInitialized.
// Could just be Call() since the parameter is optional. <-- Needs testing to be sure.
hr, _, _ := procCoInitialize.Call(uintptr(0))
if hr != 0 {
err = NewError(hr)
}
return
}
// coInitializeEx initializes COM library with concurrency model.
func coInitializeEx(coinit uint32) (err error) {
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms695279(v=vs.85).aspx
// Suggests that the first parameter is not only optional but should always be NULL.
hr, _, _ := procCoInitializeEx.Call(uintptr(0), uintptr(coinit))
if hr != 0 {
err = NewError(hr)
}
return
}
// CoInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func CoInitialize(p uintptr) (err error) {
// p is ignored and won't be used.
// Avoid any variable not used errors.
p = uintptr(0)
return coInitialize()
}
// CoInitializeEx initializes COM library with concurrency model.
func CoInitializeEx(p uintptr, coinit uint32) (err error) {
// Avoid any variable not used errors.
p = uintptr(0)
return coInitializeEx(coinit)
}
// CoUninitialize uninitializes COM Library.
func CoUninitialize() {
procCoUninitialize.Call()
}
// CoTaskMemFree frees memory pointer.
func CoTaskMemFree(memptr uintptr) {
procCoTaskMemFree.Call(memptr)
}
// CLSIDFromProgID retrieves Class Identifier with the given Program Identifier.
//
// The Programmatic Identifier must be registered, because it will be looked up
// in the Windows Registry. The registry entry has the following keys: CLSID,
// Insertable, Protocol and Shell
// (https://msdn.microsoft.com/en-us/library/dd542719(v=vs.85).aspx).
//
// programID identifies the class id with less precision and is not guaranteed
// to be unique. These are usually found in the registry under
// HKEY_LOCAL_MACHINE\SOFTWARE\Classes, usually with the format of
// "Program.Component.Version" with version being optional.
//
// CLSIDFromProgID in Windows API.
func CLSIDFromProgID(progId string) (clsid *GUID, err error) {
var guid GUID
lpszProgID := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(progId)))
hr, _, _ := procCLSIDFromProgID.Call(lpszProgID, uintptr(unsafe.Pointer(&guid)))
if hr != 0 {
err = NewError(hr)
}
clsid = &guid
return
}
// CLSIDFromString retrieves Class ID from string representation.
//
// This is technically the string version of the GUID and will convert the
// string to object.
//
// CLSIDFromString in Windows API.
func CLSIDFromString(str string) (clsid *GUID, err error) {
var guid GUID
lpsz := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str)))
hr, _, _ := procCLSIDFromString.Call(lpsz, uintptr(unsafe.Pointer(&guid)))
if hr != 0 {
err = NewError(hr)
}
clsid = &guid
return
}
// StringFromCLSID returns GUID formated string from GUID object.
func StringFromCLSID(clsid *GUID) (str string, err error) {
var p *uint16
hr, _, _ := procStringFromCLSID.Call(uintptr(unsafe.Pointer(clsid)), uintptr(unsafe.Pointer(&p)))
if hr != 0 {
err = NewError(hr)
}
str = LpOleStrToString(p)
return
}
// IIDFromString returns GUID from program ID.
func IIDFromString(progId string) (clsid *GUID, err error) {
var guid GUID
lpsz := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(progId)))
hr, _, _ := procIIDFromString.Call(lpsz, uintptr(unsafe.Pointer(&guid)))
if hr != 0 {
err = NewError(hr)
}
clsid = &guid
return
}
// StringFromIID returns GUID formatted string from GUID object.
func StringFromIID(iid *GUID) (str string, err error) {
var p *uint16
hr, _, _ := procStringFromIID.Call(uintptr(unsafe.Pointer(iid)), uintptr(unsafe.Pointer(&p)))
if hr != 0 {
err = NewError(hr)
}
str = LpOleStrToString(p)
return
}
// CreateInstance of single uninitialized object with GUID.
func CreateInstance(clsid *GUID, iid *GUID) (unk *IUnknown, err error) {
if iid == nil {
iid = IID_IUnknown
}
hr, _, _ := procCoCreateInstance.Call(
uintptr(unsafe.Pointer(clsid)),
0,
CLSCTX_SERVER,
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&unk)))
if hr != 0 {
err = NewError(hr)
}
return
}
// GetActiveObject retrieves pointer to active object.
func GetActiveObject(clsid *GUID, iid *GUID) (unk *IUnknown, err error) {
if iid == nil {
iid = IID_IUnknown
}
hr, _, _ := procGetActiveObject.Call(
uintptr(unsafe.Pointer(clsid)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&unk)))
if hr != 0 {
err = NewError(hr)
}
return
}
// VariantInit initializes variant.
func VariantInit(v *VARIANT) (err error) {
hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
err = NewError(hr)
}
return
}
// VariantClear clears value in Variant settings to VT_EMPTY.
func VariantClear(v *VARIANT) (err error) {
hr, _, _ := procVariantClear.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
err = NewError(hr)
}
return
}
// SysAllocString allocates memory for string and copies string into memory.
func SysAllocString(v string) (ss *int16) {
pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
ss = (*int16)(unsafe.Pointer(pss))
return
}
// SysAllocStringLen copies up to length of given string returning pointer.
func SysAllocStringLen(v string) (ss *int16) {
utf16 := utf16.Encode([]rune(v + "\x00"))
ptr := &utf16[0]
pss, _, _ := procSysAllocStringLen.Call(uintptr(unsafe.Pointer(ptr)), uintptr(len(utf16)-1))
ss = (*int16)(unsafe.Pointer(pss))
return
}
// SysFreeString frees string system memory. This must be called with SysAllocString.
func SysFreeString(v *int16) (err error) {
hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
err = NewError(hr)
}
return
}
// SysStringLen is the length of the system allocated string.
func SysStringLen(v *int16) uint32 {
l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
return uint32(l)
}
// CreateStdDispatch provides default IDispatch implementation for IUnknown.
//
// This handles default IDispatch implementation for objects. It haves a few
// limitations with only supporting one language. It will also only return
// default exception codes.
func CreateStdDispatch(unk *IUnknown, v uintptr, ptinfo *IUnknown) (disp *IDispatch, err error) {
hr, _, _ := procCreateStdDispatch.Call(
uintptr(unsafe.Pointer(unk)),
v,
uintptr(unsafe.Pointer(ptinfo)),
uintptr(unsafe.Pointer(&disp)))
if hr != 0 {
err = NewError(hr)
}
return
}
// CreateDispTypeInfo provides default ITypeInfo implementation for IDispatch.
//
// This will not handle the full implementation of the interface.
func CreateDispTypeInfo(idata *INTERFACEDATA) (pptinfo *IUnknown, err error) {
hr, _, _ := procCreateDispTypeInfo.Call(
uintptr(unsafe.Pointer(idata)),
uintptr(GetUserDefaultLCID()),
uintptr(unsafe.Pointer(&pptinfo)))
if hr != 0 {
err = NewError(hr)
}
return
}
// copyMemory moves location of a block of memory.
func copyMemory(dest unsafe.Pointer, src unsafe.Pointer, length uint32) {
procCopyMemory.Call(uintptr(dest), uintptr(src), uintptr(length))
}
// GetUserDefaultLCID retrieves current user default locale.
func GetUserDefaultLCID() (lcid uint32) {
ret, _, _ := procGetUserDefaultLCID.Call()
lcid = uint32(ret)
return
}
// GetMessage in message queue from runtime.
//
// This function appears to block. PeekMessage does not block.
func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) {
r0, _, err := procGetMessageW.Call(uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax))
ret = int32(r0)
return
}
// DispatchMessage to window procedure.
func DispatchMessage(msg *Msg) (ret int32) {
r0, _, _ := procDispatchMessageW.Call(uintptr(unsafe.Pointer(msg)))
ret = int32(r0)
return
}
// GetVariantDate converts COM Variant Time value to Go time.Time.
func GetVariantDate(value float64) (time.Time, error) {
var st syscall.Systemtime
r, _, _ := procVariantTimeToSystemTime.Call(uintptr(value), uintptr(unsafe.Pointer(&st)))
if r != 0 {
return time.Date(int(st.Year), time.Month(st.Month), int(st.Day), int(st.Hour), int(st.Minute), int(st.Second), int(st.Milliseconds/1000), time.UTC), nil
}
return time.Now(), errors.New("Could not convert to time, passing current time.")
}

174
vendor/github.com/go-ole/go-ole/com_func.go generated vendored Normal file
View File

@ -0,0 +1,174 @@
// +build !windows
package ole
import (
"time"
"unsafe"
)
// coInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func coInitialize() error {
return NewError(E_NOTIMPL)
}
// coInitializeEx initializes COM library with concurrency model.
func coInitializeEx(coinit uint32) error {
return NewError(E_NOTIMPL)
}
// CoInitialize initializes COM library on current thread.
//
// MSDN documentation suggests that this function should not be called. Call
// CoInitializeEx() instead. The reason has to do with threading and this
// function is only for single-threaded apartments.
//
// That said, most users of the library have gotten away with just this
// function. If you are experiencing threading issues, then use
// CoInitializeEx().
func CoInitialize(p uintptr) error {
return NewError(E_NOTIMPL)
}
// CoInitializeEx initializes COM library with concurrency model.
func CoInitializeEx(p uintptr, coinit uint32) error {
return NewError(E_NOTIMPL)
}
// CoUninitialize uninitializes COM Library.
func CoUninitialize() {}
// CoTaskMemFree frees memory pointer.
func CoTaskMemFree(memptr uintptr) {}
// CLSIDFromProgID retrieves Class Identifier with the given Program Identifier.
//
// The Programmatic Identifier must be registered, because it will be looked up
// in the Windows Registry. The registry entry has the following keys: CLSID,
// Insertable, Protocol and Shell
// (https://msdn.microsoft.com/en-us/library/dd542719(v=vs.85).aspx).
//
// programID identifies the class id with less precision and is not guaranteed
// to be unique. These are usually found in the registry under
// HKEY_LOCAL_MACHINE\SOFTWARE\Classes, usually with the format of
// "Program.Component.Version" with version being optional.
//
// CLSIDFromProgID in Windows API.
func CLSIDFromProgID(progId string) (*GUID, error) {
return nil, NewError(E_NOTIMPL)
}
// CLSIDFromString retrieves Class ID from string representation.
//
// This is technically the string version of the GUID and will convert the
// string to object.
//
// CLSIDFromString in Windows API.
func CLSIDFromString(str string) (*GUID, error) {
return nil, NewError(E_NOTIMPL)
}
// StringFromCLSID returns GUID formated string from GUID object.
func StringFromCLSID(clsid *GUID) (string, error) {
return "", NewError(E_NOTIMPL)
}
// IIDFromString returns GUID from program ID.
func IIDFromString(progId string) (*GUID, error) {
return nil, NewError(E_NOTIMPL)
}
// StringFromIID returns GUID formatted string from GUID object.
func StringFromIID(iid *GUID) (string, error) {
return "", NewError(E_NOTIMPL)
}
// CreateInstance of single uninitialized object with GUID.
func CreateInstance(clsid *GUID, iid *GUID) (*IUnknown, error) {
return nil, NewError(E_NOTIMPL)
}
// GetActiveObject retrieves pointer to active object.
func GetActiveObject(clsid *GUID, iid *GUID) (*IUnknown, error) {
return nil, NewError(E_NOTIMPL)
}
// VariantInit initializes variant.
func VariantInit(v *VARIANT) error {
return NewError(E_NOTIMPL)
}
// VariantClear clears value in Variant settings to VT_EMPTY.
func VariantClear(v *VARIANT) error {
return NewError(E_NOTIMPL)
}
// SysAllocString allocates memory for string and copies string into memory.
func SysAllocString(v string) *int16 {
u := int16(0)
return &u
}
// SysAllocStringLen copies up to length of given string returning pointer.
func SysAllocStringLen(v string) *int16 {
u := int16(0)
return &u
}
// SysFreeString frees string system memory. This must be called with SysAllocString.
func SysFreeString(v *int16) error {
return NewError(E_NOTIMPL)
}
// SysStringLen is the length of the system allocated string.
func SysStringLen(v *int16) uint32 {
return uint32(0)
}
// CreateStdDispatch provides default IDispatch implementation for IUnknown.
//
// This handles default IDispatch implementation for objects. It haves a few
// limitations with only supporting one language. It will also only return
// default exception codes.
func CreateStdDispatch(unk *IUnknown, v uintptr, ptinfo *IUnknown) (*IDispatch, error) {
return nil, NewError(E_NOTIMPL)
}
// CreateDispTypeInfo provides default ITypeInfo implementation for IDispatch.
//
// This will not handle the full implementation of the interface.
func CreateDispTypeInfo(idata *INTERFACEDATA) (*IUnknown, error) {
return nil, NewError(E_NOTIMPL)
}
// copyMemory moves location of a block of memory.
func copyMemory(dest unsafe.Pointer, src unsafe.Pointer, length uint32) {}
// GetUserDefaultLCID retrieves current user default locale.
func GetUserDefaultLCID() uint32 {
return uint32(0)
}
// GetMessage in message queue from runtime.
//
// This function appears to block. PeekMessage does not block.
func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (int32, error) {
return int32(0), NewError(E_NOTIMPL)
}
// DispatchMessage to window procedure.
func DispatchMessage(msg *Msg) int32 {
return int32(0)
}
func GetVariantDate(value float64) (time.Time, error) {
return time.Now(), NewError(E_NOTIMPL)
}

192
vendor/github.com/go-ole/go-ole/connect.go generated vendored Normal file
View File

@ -0,0 +1,192 @@
package ole
// Connection contains IUnknown for fluent interface interaction.
//
// Deprecated. Use oleutil package instead.
type Connection struct {
Object *IUnknown // Access COM
}
// Initialize COM.
func (*Connection) Initialize() (err error) {
return coInitialize()
}
// Uninitialize COM.
func (*Connection) Uninitialize() {
CoUninitialize()
}
// Create IUnknown object based first on ProgId and then from String.
func (c *Connection) Create(progId string) (err error) {
var clsid *GUID
clsid, err = CLSIDFromProgID(progId)
if err != nil {
clsid, err = CLSIDFromString(progId)
if err != nil {
return
}
}
unknown, err := CreateInstance(clsid, IID_IUnknown)
if err != nil {
return
}
c.Object = unknown
return
}
// Release IUnknown object.
func (c *Connection) Release() {
c.Object.Release()
}
// Load COM object from list of programIDs or strings.
func (c *Connection) Load(names ...string) (errors []error) {
var tempErrors []error = make([]error, len(names))
var numErrors int = 0
for _, name := range names {
err := c.Create(name)
if err != nil {
tempErrors = append(tempErrors, err)
numErrors += 1
continue
}
break
}
copy(errors, tempErrors[0:numErrors])
return
}
// Dispatch returns Dispatch object.
func (c *Connection) Dispatch() (object *Dispatch, err error) {
dispatch, err := c.Object.QueryInterface(IID_IDispatch)
if err != nil {
return
}
object = &Dispatch{dispatch}
return
}
// Dispatch stores IDispatch object.
type Dispatch struct {
Object *IDispatch // Dispatch object.
}
// Call method on IDispatch with parameters.
func (d *Dispatch) Call(method string, params ...interface{}) (result *VARIANT, err error) {
id, err := d.GetId(method)
if err != nil {
return
}
result, err = d.Invoke(id, DISPATCH_METHOD, params)
return
}
// MustCall method on IDispatch with parameters.
func (d *Dispatch) MustCall(method string, params ...interface{}) (result *VARIANT) {
id, err := d.GetId(method)
if err != nil {
panic(err)
}
result, err = d.Invoke(id, DISPATCH_METHOD, params)
if err != nil {
panic(err)
}
return
}
// Get property on IDispatch with parameters.
func (d *Dispatch) Get(name string, params ...interface{}) (result *VARIANT, err error) {
id, err := d.GetId(name)
if err != nil {
return
}
result, err = d.Invoke(id, DISPATCH_PROPERTYGET, params)
return
}
// MustGet property on IDispatch with parameters.
func (d *Dispatch) MustGet(name string, params ...interface{}) (result *VARIANT) {
id, err := d.GetId(name)
if err != nil {
panic(err)
}
result, err = d.Invoke(id, DISPATCH_PROPERTYGET, params)
if err != nil {
panic(err)
}
return
}
// Set property on IDispatch with parameters.
func (d *Dispatch) Set(name string, params ...interface{}) (result *VARIANT, err error) {
id, err := d.GetId(name)
if err != nil {
return
}
result, err = d.Invoke(id, DISPATCH_PROPERTYPUT, params)
return
}
// MustSet property on IDispatch with parameters.
func (d *Dispatch) MustSet(name string, params ...interface{}) (result *VARIANT) {
id, err := d.GetId(name)
if err != nil {
panic(err)
}
result, err = d.Invoke(id, DISPATCH_PROPERTYPUT, params)
if err != nil {
panic(err)
}
return
}
// GetId retrieves ID of name on IDispatch.
func (d *Dispatch) GetId(name string) (id int32, err error) {
var dispid []int32
dispid, err = d.Object.GetIDsOfName([]string{name})
if err != nil {
return
}
id = dispid[0]
return
}
// GetIds retrieves all IDs of names on IDispatch.
func (d *Dispatch) GetIds(names ...string) (dispid []int32, err error) {
dispid, err = d.Object.GetIDsOfName(names)
return
}
// Invoke IDispatch on DisplayID of dispatch type with parameters.
//
// There have been problems where if send cascading params..., it would error
// out because the parameters would be empty.
func (d *Dispatch) Invoke(id int32, dispatch int16, params []interface{}) (result *VARIANT, err error) {
if len(params) < 1 {
result, err = d.Object.Invoke(id, dispatch)
} else {
result, err = d.Object.Invoke(id, dispatch, params...)
}
return
}
// Release IDispatch object.
func (d *Dispatch) Release() {
d.Object.Release()
}
// Connect initializes COM and attempts to load IUnknown based on given names.
func Connect(names ...string) (connection *Connection) {
connection.Initialize()
connection.Load(names...)
return
}

153
vendor/github.com/go-ole/go-ole/constants.go generated vendored Normal file
View File

@ -0,0 +1,153 @@
package ole
const (
CLSCTX_INPROC_SERVER = 1
CLSCTX_INPROC_HANDLER = 2
CLSCTX_LOCAL_SERVER = 4
CLSCTX_INPROC_SERVER16 = 8
CLSCTX_REMOTE_SERVER = 16
CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
)
const (
COINIT_APARTMENTTHREADED = 0x2
COINIT_MULTITHREADED = 0x0
COINIT_DISABLE_OLE1DDE = 0x4
COINIT_SPEED_OVER_MEMORY = 0x8
)
const (
DISPATCH_METHOD = 1
DISPATCH_PROPERTYGET = 2
DISPATCH_PROPERTYPUT = 4
DISPATCH_PROPERTYPUTREF = 8
)
const (
S_OK = 0x00000000
E_UNEXPECTED = 0x8000FFFF
E_NOTIMPL = 0x80004001
E_OUTOFMEMORY = 0x8007000E
E_INVALIDARG = 0x80070057
E_NOINTERFACE = 0x80004002
E_POINTER = 0x80004003
E_HANDLE = 0x80070006
E_ABORT = 0x80004004
E_FAIL = 0x80004005
E_ACCESSDENIED = 0x80070005
E_PENDING = 0x8000000A
CO_E_CLASSSTRING = 0x800401F3
)
const (
CC_FASTCALL = iota
CC_CDECL
CC_MSCPASCAL
CC_PASCAL = CC_MSCPASCAL
CC_MACPASCAL
CC_STDCALL
CC_FPFASTCALL
CC_SYSCALL
CC_MPWCDECL
CC_MPWPASCAL
CC_MAX = CC_MPWPASCAL
)
type VT uint16
const (
VT_EMPTY VT = 0x0
VT_NULL VT = 0x1
VT_I2 VT = 0x2
VT_I4 VT = 0x3
VT_R4 VT = 0x4
VT_R8 VT = 0x5
VT_CY VT = 0x6
VT_DATE VT = 0x7
VT_BSTR VT = 0x8
VT_DISPATCH VT = 0x9
VT_ERROR VT = 0xa
VT_BOOL VT = 0xb
VT_VARIANT VT = 0xc
VT_UNKNOWN VT = 0xd
VT_DECIMAL VT = 0xe
VT_I1 VT = 0x10
VT_UI1 VT = 0x11
VT_UI2 VT = 0x12
VT_UI4 VT = 0x13
VT_I8 VT = 0x14
VT_UI8 VT = 0x15
VT_INT VT = 0x16
VT_UINT VT = 0x17
VT_VOID VT = 0x18
VT_HRESULT VT = 0x19
VT_PTR VT = 0x1a
VT_SAFEARRAY VT = 0x1b
VT_CARRAY VT = 0x1c
VT_USERDEFINED VT = 0x1d
VT_LPSTR VT = 0x1e
VT_LPWSTR VT = 0x1f
VT_RECORD VT = 0x24
VT_INT_PTR VT = 0x25
VT_UINT_PTR VT = 0x26
VT_FILETIME VT = 0x40
VT_BLOB VT = 0x41
VT_STREAM VT = 0x42
VT_STORAGE VT = 0x43
VT_STREAMED_OBJECT VT = 0x44
VT_STORED_OBJECT VT = 0x45
VT_BLOB_OBJECT VT = 0x46
VT_CF VT = 0x47
VT_CLSID VT = 0x48
VT_BSTR_BLOB VT = 0xfff
VT_VECTOR VT = 0x1000
VT_ARRAY VT = 0x2000
VT_BYREF VT = 0x4000
VT_RESERVED VT = 0x8000
VT_ILLEGAL VT = 0xffff
VT_ILLEGALMASKED VT = 0xfff
VT_TYPEMASK VT = 0xfff
)
const (
DISPID_UNKNOWN = -1
DISPID_VALUE = 0
DISPID_PROPERTYPUT = -3
DISPID_NEWENUM = -4
DISPID_EVALUATE = -5
DISPID_CONSTRUCTOR = -6
DISPID_DESTRUCTOR = -7
DISPID_COLLECT = -8
)
const (
TKIND_ENUM = 1
TKIND_RECORD = 2
TKIND_MODULE = 3
TKIND_INTERFACE = 4
TKIND_DISPATCH = 5
TKIND_COCLASS = 6
TKIND_ALIAS = 7
TKIND_UNION = 8
TKIND_MAX = 9
)
// Safe Array Feature Flags
const (
FADF_AUTO = 0x0001
FADF_STATIC = 0x0002
FADF_EMBEDDED = 0x0004
FADF_FIXEDSIZE = 0x0010
FADF_RECORD = 0x0020
FADF_HAVEIID = 0x0040
FADF_HAVEVARTYPE = 0x0080
FADF_BSTR = 0x0100
FADF_UNKNOWN = 0x0200
FADF_DISPATCH = 0x0400
FADF_VARIANT = 0x0800
FADF_RESERVED = 0xF008
)

51
vendor/github.com/go-ole/go-ole/error.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
package ole
// OleError stores COM errors.
type OleError struct {
hr uintptr
description string
subError error
}
// NewError creates new error with HResult.
func NewError(hr uintptr) *OleError {
return &OleError{hr: hr}
}
// NewErrorWithDescription creates new COM error with HResult and description.
func NewErrorWithDescription(hr uintptr, description string) *OleError {
return &OleError{hr: hr, description: description}
}
// NewErrorWithSubError creates new COM error with parent error.
func NewErrorWithSubError(hr uintptr, description string, err error) *OleError {
return &OleError{hr: hr, description: description, subError: err}
}
// Code is the HResult.
func (v *OleError) Code() uintptr {
return uintptr(v.hr)
}
// String description, either manually set or format message with error code.
func (v *OleError) String() string {
if v.description != "" {
return errstr(int(v.hr)) + " (" + v.description + ")"
}
return errstr(int(v.hr))
}
// Error implements error interface.
func (v *OleError) Error() string {
return v.String()
}
// Description retrieves error summary, if there is one.
func (v *OleError) Description() string {
return v.description
}
// SubError returns parent error, if there is one.
func (v *OleError) SubError() error {
return v.subError
}

8
vendor/github.com/go-ole/go-ole/error_func.go generated vendored Normal file
View File

@ -0,0 +1,8 @@
// +build !windows
package ole
// errstr converts error code to string.
func errstr(errno int) string {
return ""
}

24
vendor/github.com/go-ole/go-ole/error_windows.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
// +build windows
package ole
import (
"fmt"
"syscall"
"unicode/utf16"
)
// errstr converts error code to string.
func errstr(errno int) string {
// ask windows for the remaining errors
var flags uint32 = syscall.FORMAT_MESSAGE_FROM_SYSTEM | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
b := make([]uint16, 300)
n, err := syscall.FormatMessage(flags, 0, uint32(errno), 0, b, nil)
if err != nil {
return fmt.Sprintf("error %d (FormatMessage failed with: %v)", errno, err)
}
// trim terminating \r and \n
for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
}
return string(utf16.Decode(b[:n]))
}

Some files were not shown because too many files have changed in this diff Show More