Initial commit
This commit is contained in:
commit
48b34bca9d
102 changed files with 278172 additions and 0 deletions
12
Makefile
Normal file
12
Makefile
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt:
|
||||||
|
go fmt ./...
|
||||||
|
|
||||||
|
.PHONY: mod
|
||||||
|
mod:
|
||||||
|
go mod vendor
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
go test -v -race ./...
|
14
go.mod
Normal file
14
go.mod
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
module git.ctrlz.es/mgdelacroix/rmsn
|
||||||
|
|
||||||
|
go 1.17
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.8
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
|
)
|
15
go.sum
Normal file
15
go.sum
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
7
model/game.go
Normal file
7
model/game.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
ID int
|
||||||
|
UserID int
|
||||||
|
Name string
|
||||||
|
}
|
12
model/game_member.go
Normal file
12
model/game_member.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleGameMaster = "role_game_master"
|
||||||
|
RolePlayer = "role_player"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GameMember struct {
|
||||||
|
GameID int
|
||||||
|
UserID int
|
||||||
|
Role string
|
||||||
|
}
|
9
model/user.go
Normal file
9
model/user.go
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Mail string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
71
services/store/store.go
Normal file
71
services/store/store.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Store struct {
|
||||||
|
Path string
|
||||||
|
Conn *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func addPathOptions(path string) string {
|
||||||
|
if !strings.HasPrefix(path, ":memory:") {
|
||||||
|
path = "file:" + path
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s?_foreign_keys=true", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStore(path string) (*Store, error) {
|
||||||
|
s := &Store{Path: path}
|
||||||
|
|
||||||
|
conn, err := sql.Open("sqlite3", addPathOptions(path))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.EnsureSchema(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Conn = conn
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) Close() error {
|
||||||
|
return s.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) EnsureSchema() error {
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
mail VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
username VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
password VARCHAR(255) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS game (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS gamemember (
|
||||||
|
game_id INTEGER NOT NULL,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
role VARCHAR(255) NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (game_id, user_id)
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err := s.Conn.Exec(schema)
|
||||||
|
return err
|
||||||
|
}
|
32
services/store/store_test.go
Normal file
32
services/store/store_test.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddPathOptions(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
Name string
|
||||||
|
Path string
|
||||||
|
Expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Path is memory",
|
||||||
|
Path: ":memory:",
|
||||||
|
Expected: ":memory:?_foreign_keys=true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Path is a file path",
|
||||||
|
Path: "./some_file.sqlite",
|
||||||
|
Expected: "file:./some_file.sqlite?_foreign_keys=true",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
require.Equal(t, tc.Expected, addPathOptions(tc.Path))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
15
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
Normal file
15
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
145
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
Normal file
145
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||||
|
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
||||||
|
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
||||||
|
// tag is deprecated and thus should not be used.
|
||||||
|
// Go versions prior to 1.4 are disabled because they use a different layout
|
||||||
|
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
||||||
|
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UnsafeDisabled is a build-time constant which specifies whether or
|
||||||
|
// not access to the unsafe package is available.
|
||||||
|
UnsafeDisabled = false
|
||||||
|
|
||||||
|
// ptrSize is the size of a pointer on the current arch.
|
||||||
|
ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||||
|
)
|
||||||
|
|
||||||
|
type flag uintptr
|
||||||
|
|
||||||
|
var (
|
||||||
|
// flagRO indicates whether the value field of a reflect.Value
|
||||||
|
// is read-only.
|
||||||
|
flagRO flag
|
||||||
|
|
||||||
|
// flagAddr indicates whether the address of the reflect.Value's
|
||||||
|
// value may be taken.
|
||||||
|
flagAddr flag
|
||||||
|
)
|
||||||
|
|
||||||
|
// flagKindMask holds the bits that make up the kind
|
||||||
|
// part of the flags field. In all the supported versions,
|
||||||
|
// it is in the lower 5 bits.
|
||||||
|
const flagKindMask = flag(0x1f)
|
||||||
|
|
||||||
|
// Different versions of Go have used different
|
||||||
|
// bit layouts for the flags type. This table
|
||||||
|
// records the known combinations.
|
||||||
|
var okFlags = []struct {
|
||||||
|
ro, addr flag
|
||||||
|
}{{
|
||||||
|
// From Go 1.4 to 1.5
|
||||||
|
ro: 1 << 5,
|
||||||
|
addr: 1 << 7,
|
||||||
|
}, {
|
||||||
|
// Up to Go tip.
|
||||||
|
ro: 1<<5 | 1<<6,
|
||||||
|
addr: 1 << 8,
|
||||||
|
}}
|
||||||
|
|
||||||
|
var flagValOffset = func() uintptr {
|
||||||
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||||
|
if !ok {
|
||||||
|
panic("reflect.Value has no flag field")
|
||||||
|
}
|
||||||
|
return field.Offset
|
||||||
|
}()
|
||||||
|
|
||||||
|
// flagField returns a pointer to the flag field of a reflect.Value.
|
||||||
|
func flagField(v *reflect.Value) *flag {
|
||||||
|
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
||||||
|
// the typical safety restrictions preventing access to unaddressable and
|
||||||
|
// unexported data. It works by digging the raw pointer to the underlying
|
||||||
|
// value out of the protected value and generating a new unprotected (unsafe)
|
||||||
|
// reflect.Value to it.
|
||||||
|
//
|
||||||
|
// This allows us to check for implementations of the Stringer and error
|
||||||
|
// interfaces to be used for pretty printing ordinarily unaddressable and
|
||||||
|
// inaccessible values such as unexported struct fields.
|
||||||
|
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||||
|
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
flagFieldPtr := flagField(&v)
|
||||||
|
*flagFieldPtr &^= flagRO
|
||||||
|
*flagFieldPtr |= flagAddr
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity checks against future reflect package changes
|
||||||
|
// to the type or semantics of the Value.flag field.
|
||||||
|
func init() {
|
||||||
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||||
|
if !ok {
|
||||||
|
panic("reflect.Value has no flag field")
|
||||||
|
}
|
||||||
|
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
|
||||||
|
panic("reflect.Value flag field has changed kind")
|
||||||
|
}
|
||||||
|
type t0 int
|
||||||
|
var t struct {
|
||||||
|
A t0
|
||||||
|
// t0 will have flagEmbedRO set.
|
||||||
|
t0
|
||||||
|
// a will have flagStickyRO set
|
||||||
|
a t0
|
||||||
|
}
|
||||||
|
vA := reflect.ValueOf(t).FieldByName("A")
|
||||||
|
va := reflect.ValueOf(t).FieldByName("a")
|
||||||
|
vt0 := reflect.ValueOf(t).FieldByName("t0")
|
||||||
|
|
||||||
|
// Infer flagRO from the difference between the flags
|
||||||
|
// for the (otherwise identical) fields in t.
|
||||||
|
flagPublic := *flagField(&vA)
|
||||||
|
flagWithRO := *flagField(&va) | *flagField(&vt0)
|
||||||
|
flagRO = flagPublic ^ flagWithRO
|
||||||
|
|
||||||
|
// Infer flagAddr from the difference between a value
|
||||||
|
// taken from a pointer and not.
|
||||||
|
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
|
||||||
|
flagNoPtr := *flagField(&vA)
|
||||||
|
flagPtr := *flagField(&vPtrA)
|
||||||
|
flagAddr = flagNoPtr ^ flagPtr
|
||||||
|
|
||||||
|
// Check that the inferred flags tally with one of the known versions.
|
||||||
|
for _, f := range okFlags {
|
||||||
|
if flagRO == f.ro && flagAddr == f.addr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("reflect.Value read-only flag has changed semantics")
|
||||||
|
}
|
38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
Normal file
38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||||
|
// when the code is running on Google App Engine, compiled by GopherJS, or
|
||||||
|
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
||||||
|
// tag is deprecated and thus should not be used.
|
||||||
|
// +build js appengine safe disableunsafe !go1.4
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UnsafeDisabled is a build-time constant which specifies whether or
|
||||||
|
// not access to the unsafe package is available.
|
||||||
|
UnsafeDisabled = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// unsafeReflectValue typically converts the passed reflect.Value into a one
|
||||||
|
// that bypasses the typical safety restrictions preventing access to
|
||||||
|
// unaddressable and unexported data. However, doing this relies on access to
|
||||||
|
// the unsafe package. This is a stub version which simply returns the passed
|
||||||
|
// reflect.Value when the unsafe package is not available.
|
||||||
|
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||||
|
return v
|
||||||
|
}
|
341
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
Normal file
341
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
Normal file
|
@ -0,0 +1,341 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Some constants in the form of bytes to avoid string overhead. This mirrors
|
||||||
|
// the technique used in the fmt package.
|
||||||
|
var (
|
||||||
|
panicBytes = []byte("(PANIC=")
|
||||||
|
plusBytes = []byte("+")
|
||||||
|
iBytes = []byte("i")
|
||||||
|
trueBytes = []byte("true")
|
||||||
|
falseBytes = []byte("false")
|
||||||
|
interfaceBytes = []byte("(interface {})")
|
||||||
|
commaNewlineBytes = []byte(",\n")
|
||||||
|
newlineBytes = []byte("\n")
|
||||||
|
openBraceBytes = []byte("{")
|
||||||
|
openBraceNewlineBytes = []byte("{\n")
|
||||||
|
closeBraceBytes = []byte("}")
|
||||||
|
asteriskBytes = []byte("*")
|
||||||
|
colonBytes = []byte(":")
|
||||||
|
colonSpaceBytes = []byte(": ")
|
||||||
|
openParenBytes = []byte("(")
|
||||||
|
closeParenBytes = []byte(")")
|
||||||
|
spaceBytes = []byte(" ")
|
||||||
|
pointerChainBytes = []byte("->")
|
||||||
|
nilAngleBytes = []byte("<nil>")
|
||||||
|
maxNewlineBytes = []byte("<max depth reached>\n")
|
||||||
|
maxShortBytes = []byte("<max>")
|
||||||
|
circularBytes = []byte("<already shown>")
|
||||||
|
circularShortBytes = []byte("<shown>")
|
||||||
|
invalidAngleBytes = []byte("<invalid>")
|
||||||
|
openBracketBytes = []byte("[")
|
||||||
|
closeBracketBytes = []byte("]")
|
||||||
|
percentBytes = []byte("%")
|
||||||
|
precisionBytes = []byte(".")
|
||||||
|
openAngleBytes = []byte("<")
|
||||||
|
closeAngleBytes = []byte(">")
|
||||||
|
openMapBytes = []byte("map[")
|
||||||
|
closeMapBytes = []byte("]")
|
||||||
|
lenEqualsBytes = []byte("len=")
|
||||||
|
capEqualsBytes = []byte("cap=")
|
||||||
|
)
|
||||||
|
|
||||||
|
// hexDigits is used to map a decimal value to a hex digit.
|
||||||
|
var hexDigits = "0123456789abcdef"
|
||||||
|
|
||||||
|
// catchPanic handles any panics that might occur during the handleMethods
|
||||||
|
// calls.
|
||||||
|
func catchPanic(w io.Writer, v reflect.Value) {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
w.Write(panicBytes)
|
||||||
|
fmt.Fprintf(w, "%v", err)
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMethods attempts to call the Error and String methods on the underlying
|
||||||
|
// type the passed reflect.Value represents and outputes the result to Writer w.
|
||||||
|
//
|
||||||
|
// It handles panics in any called methods by catching and displaying the error
|
||||||
|
// as the formatted value.
|
||||||
|
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
|
||||||
|
// We need an interface to check if the type implements the error or
|
||||||
|
// Stringer interface. However, the reflect package won't give us an
|
||||||
|
// interface on certain things like unexported struct fields in order
|
||||||
|
// to enforce visibility rules. We use unsafe, when it's available,
|
||||||
|
// to bypass these restrictions since this package does not mutate the
|
||||||
|
// values.
|
||||||
|
if !v.CanInterface() {
|
||||||
|
if UnsafeDisabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
v = unsafeReflectValue(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose whether or not to do error and Stringer interface lookups against
|
||||||
|
// the base type or a pointer to the base type depending on settings.
|
||||||
|
// Technically calling one of these methods with a pointer receiver can
|
||||||
|
// mutate the value, however, types which choose to satisify an error or
|
||||||
|
// Stringer interface with a pointer receiver should not be mutating their
|
||||||
|
// state inside these interface methods.
|
||||||
|
if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
|
||||||
|
v = unsafeReflectValue(v)
|
||||||
|
}
|
||||||
|
if v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it an error or Stringer?
|
||||||
|
switch iface := v.Interface().(type) {
|
||||||
|
case error:
|
||||||
|
defer catchPanic(w, v)
|
||||||
|
if cs.ContinueOnMethod {
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(iface.Error()))
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(iface.Error()))
|
||||||
|
return true
|
||||||
|
|
||||||
|
case fmt.Stringer:
|
||||||
|
defer catchPanic(w, v)
|
||||||
|
if cs.ContinueOnMethod {
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(iface.String()))
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
w.Write([]byte(iface.String()))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// printBool outputs a boolean value as true or false to Writer w.
|
||||||
|
func printBool(w io.Writer, val bool) {
|
||||||
|
if val {
|
||||||
|
w.Write(trueBytes)
|
||||||
|
} else {
|
||||||
|
w.Write(falseBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printInt outputs a signed integer value to Writer w.
|
||||||
|
func printInt(w io.Writer, val int64, base int) {
|
||||||
|
w.Write([]byte(strconv.FormatInt(val, base)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printUint outputs an unsigned integer value to Writer w.
|
||||||
|
func printUint(w io.Writer, val uint64, base int) {
|
||||||
|
w.Write([]byte(strconv.FormatUint(val, base)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printFloat outputs a floating point value using the specified precision,
|
||||||
|
// which is expected to be 32 or 64bit, to Writer w.
|
||||||
|
func printFloat(w io.Writer, val float64, precision int) {
|
||||||
|
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printComplex outputs a complex value using the specified float precision
|
||||||
|
// for the real and imaginary parts to Writer w.
|
||||||
|
func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
||||||
|
r := real(c)
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
|
||||||
|
i := imag(c)
|
||||||
|
if i >= 0 {
|
||||||
|
w.Write(plusBytes)
|
||||||
|
}
|
||||||
|
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
|
||||||
|
w.Write(iBytes)
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
|
||||||
|
// prefix to Writer w.
|
||||||
|
func printHexPtr(w io.Writer, p uintptr) {
|
||||||
|
// Null pointer.
|
||||||
|
num := uint64(p)
|
||||||
|
if num == 0 {
|
||||||
|
w.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
|
||||||
|
buf := make([]byte, 18)
|
||||||
|
|
||||||
|
// It's simpler to construct the hex string right to left.
|
||||||
|
base := uint64(16)
|
||||||
|
i := len(buf) - 1
|
||||||
|
for num >= base {
|
||||||
|
buf[i] = hexDigits[num%base]
|
||||||
|
num /= base
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
buf[i] = hexDigits[num]
|
||||||
|
|
||||||
|
// Add '0x' prefix.
|
||||||
|
i--
|
||||||
|
buf[i] = 'x'
|
||||||
|
i--
|
||||||
|
buf[i] = '0'
|
||||||
|
|
||||||
|
// Strip unused leading bytes.
|
||||||
|
buf = buf[i:]
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
|
||||||
|
// elements to be sorted.
|
||||||
|
type valuesSorter struct {
|
||||||
|
values []reflect.Value
|
||||||
|
strings []string // either nil or same len and values
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// newValuesSorter initializes a valuesSorter instance, which holds a set of
|
||||||
|
// surrogate keys on which the data should be sorted. It uses flags in
|
||||||
|
// ConfigState to decide if and how to populate those surrogate keys.
|
||||||
|
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
|
||||||
|
vs := &valuesSorter{values: values, cs: cs}
|
||||||
|
if canSortSimply(vs.values[0].Kind()) {
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
if !cs.DisableMethods {
|
||||||
|
vs.strings = make([]string, len(values))
|
||||||
|
for i := range vs.values {
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
if !handleMethods(cs, &b, vs.values[i]) {
|
||||||
|
vs.strings = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
vs.strings[i] = b.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vs.strings == nil && cs.SpewKeys {
|
||||||
|
vs.strings = make([]string, len(values))
|
||||||
|
for i := range vs.values {
|
||||||
|
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
|
||||||
|
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
|
||||||
|
// directly, or whether it should be considered for sorting by surrogate keys
|
||||||
|
// (if the ConfigState allows it).
|
||||||
|
func canSortSimply(kind reflect.Kind) bool {
|
||||||
|
// This switch parallels valueSortLess, except for the default case.
|
||||||
|
switch kind {
|
||||||
|
case reflect.Bool:
|
||||||
|
return true
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return true
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return true
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return true
|
||||||
|
case reflect.String:
|
||||||
|
return true
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return true
|
||||||
|
case reflect.Array:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of values in the slice. It is part of the
|
||||||
|
// sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Len() int {
|
||||||
|
return len(s.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap swaps the values at the passed indices. It is part of the
|
||||||
|
// sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Swap(i, j int) {
|
||||||
|
s.values[i], s.values[j] = s.values[j], s.values[i]
|
||||||
|
if s.strings != nil {
|
||||||
|
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// valueSortLess returns whether the first value should sort before the second
|
||||||
|
// value. It is used by valueSorter.Less as part of the sort.Interface
|
||||||
|
// implementation.
|
||||||
|
func valueSortLess(a, b reflect.Value) bool {
|
||||||
|
switch a.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return !a.Bool() && b.Bool()
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return a.Int() < b.Int()
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return a.Float() < b.Float()
|
||||||
|
case reflect.String:
|
||||||
|
return a.String() < b.String()
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Array:
|
||||||
|
// Compare the contents of both arrays.
|
||||||
|
l := a.Len()
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
av := a.Index(i)
|
||||||
|
bv := b.Index(i)
|
||||||
|
if av.Interface() == bv.Interface() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return valueSortLess(av, bv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a.String() < b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less returns whether the value at index i should sort before the
|
||||||
|
// value at index j. It is part of the sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Less(i, j int) bool {
|
||||||
|
if s.strings == nil {
|
||||||
|
return valueSortLess(s.values[i], s.values[j])
|
||||||
|
}
|
||||||
|
return s.strings[i] < s.strings[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortValues is a sort function that handles both native types and any type that
|
||||||
|
// can be converted to error or Stringer. Other inputs are sorted according to
|
||||||
|
// their Value.String() value to ensure display stability.
|
||||||
|
func sortValues(values []reflect.Value, cs *ConfigState) {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sort.Sort(newValuesSorter(values, cs))
|
||||||
|
}
|
306
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
Normal file
306
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigState houses the configuration options used by spew to format and
|
||||||
|
// display values. There is a global instance, Config, that is used to control
|
||||||
|
// all top-level Formatter and Dump functionality. Each ConfigState instance
|
||||||
|
// provides methods equivalent to the top-level functions.
|
||||||
|
//
|
||||||
|
// The zero value for ConfigState provides no indentation. You would typically
|
||||||
|
// want to set it to a space or a tab.
|
||||||
|
//
|
||||||
|
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
|
||||||
|
// with default settings. See the documentation of NewDefaultConfig for default
|
||||||
|
// values.
|
||||||
|
type ConfigState struct {
|
||||||
|
// Indent specifies the string to use for each indentation level. The
|
||||||
|
// global config instance that all top-level functions use set this to a
|
||||||
|
// single space by default. If you would like more indentation, you might
|
||||||
|
// set this to a tab with "\t" or perhaps two spaces with " ".
|
||||||
|
Indent string
|
||||||
|
|
||||||
|
// MaxDepth controls the maximum number of levels to descend into nested
|
||||||
|
// data structures. The default, 0, means there is no limit.
|
||||||
|
//
|
||||||
|
// NOTE: Circular data structures are properly detected, so it is not
|
||||||
|
// necessary to set this value unless you specifically want to limit deeply
|
||||||
|
// nested data structures.
|
||||||
|
MaxDepth int
|
||||||
|
|
||||||
|
// DisableMethods specifies whether or not error and Stringer interfaces are
|
||||||
|
// invoked for types that implement them.
|
||||||
|
DisableMethods bool
|
||||||
|
|
||||||
|
// DisablePointerMethods specifies whether or not to check for and invoke
|
||||||
|
// error and Stringer interfaces on types which only accept a pointer
|
||||||
|
// receiver when the current type is not a pointer.
|
||||||
|
//
|
||||||
|
// NOTE: This might be an unsafe action since calling one of these methods
|
||||||
|
// with a pointer receiver could technically mutate the value, however,
|
||||||
|
// in practice, types which choose to satisify an error or Stringer
|
||||||
|
// interface with a pointer receiver should not be mutating their state
|
||||||
|
// inside these interface methods. As a result, this option relies on
|
||||||
|
// access to the unsafe package, so it will not have any effect when
|
||||||
|
// running in environments without access to the unsafe package such as
|
||||||
|
// Google App Engine or with the "safe" build tag specified.
|
||||||
|
DisablePointerMethods bool
|
||||||
|
|
||||||
|
// DisablePointerAddresses specifies whether to disable the printing of
|
||||||
|
// pointer addresses. This is useful when diffing data structures in tests.
|
||||||
|
DisablePointerAddresses bool
|
||||||
|
|
||||||
|
// DisableCapacities specifies whether to disable the printing of capacities
|
||||||
|
// for arrays, slices, maps and channels. This is useful when diffing
|
||||||
|
// data structures in tests.
|
||||||
|
DisableCapacities bool
|
||||||
|
|
||||||
|
// ContinueOnMethod specifies whether or not recursion should continue once
|
||||||
|
// a custom error or Stringer interface is invoked. The default, false,
|
||||||
|
// means it will print the results of invoking the custom error or Stringer
|
||||||
|
// interface and return immediately instead of continuing to recurse into
|
||||||
|
// the internals of the data type.
|
||||||
|
//
|
||||||
|
// NOTE: This flag does not have any effect if method invocation is disabled
|
||||||
|
// via the DisableMethods or DisablePointerMethods options.
|
||||||
|
ContinueOnMethod bool
|
||||||
|
|
||||||
|
// SortKeys specifies map keys should be sorted before being printed. Use
|
||||||
|
// this to have a more deterministic, diffable output. Note that only
|
||||||
|
// native types (bool, int, uint, floats, uintptr and string) and types
|
||||||
|
// that support the error or Stringer interfaces (if methods are
|
||||||
|
// enabled) are supported, with other types sorted according to the
|
||||||
|
// reflect.Value.String() output which guarantees display stability.
|
||||||
|
SortKeys bool
|
||||||
|
|
||||||
|
// SpewKeys specifies that, as a last resort attempt, map keys should
|
||||||
|
// be spewed to strings and sorted by those strings. This is only
|
||||||
|
// considered if SortKeys is true.
|
||||||
|
SpewKeys bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is the active configuration of the top-level functions.
|
||||||
|
// The configuration can be changed by modifying the contents of spew.Config.
|
||||||
|
var Config = ConfigState{Indent: " "}
|
||||||
|
|
||||||
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the formatted string as a value that satisfies error. See NewFormatter
|
||||||
|
// for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
|
||||||
|
return fmt.Errorf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprint(w, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintf(w, format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintln(w, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Print(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Printf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Println(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprint(a ...interface{}) string {
|
||||||
|
return fmt.Sprint(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
|
||||||
|
return fmt.Sprintf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
||||||
|
// were passed with a Formatter interface returned by c.NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprintln(a ...interface{}) string {
|
||||||
|
return fmt.Sprintln(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
printing functions. The formatter is useful for inline printing of smaller data
|
||||||
|
types similar to the standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Typically this function shouldn't be called directly. It is much easier to make
|
||||||
|
use of the custom formatter by calling one of the convenience functions such as
|
||||||
|
c.Printf, c.Println, or c.Printf.
|
||||||
|
*/
|
||||||
|
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
|
||||||
|
return newFormatter(c, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
fdump(c, w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
|
indentation, and additional debug information such as complete types and all
|
||||||
|
pointer addresses used to indirect to the final value. It provides the
|
||||||
|
following features over the built-in printing facilities provided by the fmt
|
||||||
|
package:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
|
The configuration options are controlled by modifying the public members
|
||||||
|
of c. See ConfigState for options documentation.
|
||||||
|
|
||||||
|
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
||||||
|
get the formatted result as a string.
|
||||||
|
*/
|
||||||
|
func (c *ConfigState) Dump(a ...interface{}) {
|
||||||
|
fdump(c, os.Stdout, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sdump returns a string with the passed arguments formatted exactly the same
|
||||||
|
// as Dump.
|
||||||
|
func (c *ConfigState) Sdump(a ...interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fdump(c, &buf, a...)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgs accepts a slice of arguments and returns a slice of the same
|
||||||
|
// length with each argument converted to a spew Formatter interface using
|
||||||
|
// the ConfigState associated with s.
|
||||||
|
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
|
formatters = make([]interface{}, len(args))
|
||||||
|
for index, arg := range args {
|
||||||
|
formatters[index] = newFormatter(c, arg)
|
||||||
|
}
|
||||||
|
return formatters
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a ConfigState with the following default settings.
|
||||||
|
//
|
||||||
|
// Indent: " "
|
||||||
|
// MaxDepth: 0
|
||||||
|
// DisableMethods: false
|
||||||
|
// DisablePointerMethods: false
|
||||||
|
// ContinueOnMethod: false
|
||||||
|
// SortKeys: false
|
||||||
|
func NewDefaultConfig() *ConfigState {
|
||||||
|
return &ConfigState{Indent: " "}
|
||||||
|
}
|
211
vendor/github.com/davecgh/go-spew/spew/doc.go
generated
vendored
Normal file
211
vendor/github.com/davecgh/go-spew/spew/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package spew implements a deep pretty printer for Go data structures to aid in
|
||||||
|
debugging.
|
||||||
|
|
||||||
|
A quick overview of the additional features spew provides over the built-in
|
||||||
|
printing facilities for Go data types are as follows:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output (only when using
|
||||||
|
Dump style)
|
||||||
|
|
||||||
|
There are two different approaches spew allows for dumping Go data structures:
|
||||||
|
|
||||||
|
* Dump style which prints with newlines, customizable indentation,
|
||||||
|
and additional debug information such as types and all pointer addresses
|
||||||
|
used to indirect to the final value
|
||||||
|
* A custom Formatter interface that integrates cleanly with the standard fmt
|
||||||
|
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
|
||||||
|
similar to the default %v while providing the additional functionality
|
||||||
|
outlined above and passing unsupported format verbs such as %x and %q
|
||||||
|
along to fmt
|
||||||
|
|
||||||
|
Quick Start
|
||||||
|
|
||||||
|
This section demonstrates how to quickly get started with spew. See the
|
||||||
|
sections below for further details on formatting and configuration options.
|
||||||
|
|
||||||
|
To dump a variable with full newlines, indentation, type, and pointer
|
||||||
|
information use Dump, Fdump, or Sdump:
|
||||||
|
spew.Dump(myVar1, myVar2, ...)
|
||||||
|
spew.Fdump(someWriter, myVar1, myVar2, ...)
|
||||||
|
str := spew.Sdump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
Alternatively, if you would prefer to use format strings with a compacted inline
|
||||||
|
printing style, use the convenience wrappers Printf, Fprintf, etc with
|
||||||
|
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
|
||||||
|
%#+v (adds types and pointer addresses):
|
||||||
|
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
|
||||||
|
Configuration Options
|
||||||
|
|
||||||
|
Configuration of spew is handled by fields in the ConfigState type. For
|
||||||
|
convenience, all of the top-level functions use a global state available
|
||||||
|
via the spew.Config global.
|
||||||
|
|
||||||
|
It is also possible to create a ConfigState instance that provides methods
|
||||||
|
equivalent to the top-level functions. This allows concurrent configuration
|
||||||
|
options. See the ConfigState documentation for more details.
|
||||||
|
|
||||||
|
The following configuration options are available:
|
||||||
|
* Indent
|
||||||
|
String to use for each indentation level for Dump functions.
|
||||||
|
It is a single space by default. A popular alternative is "\t".
|
||||||
|
|
||||||
|
* MaxDepth
|
||||||
|
Maximum number of levels to descend into nested data structures.
|
||||||
|
There is no limit by default.
|
||||||
|
|
||||||
|
* DisableMethods
|
||||||
|
Disables invocation of error and Stringer interface methods.
|
||||||
|
Method invocation is enabled by default.
|
||||||
|
|
||||||
|
* DisablePointerMethods
|
||||||
|
Disables invocation of error and Stringer interface methods on types
|
||||||
|
which only accept pointer receivers from non-pointer variables.
|
||||||
|
Pointer method invocation is enabled by default.
|
||||||
|
|
||||||
|
* DisablePointerAddresses
|
||||||
|
DisablePointerAddresses specifies whether to disable the printing of
|
||||||
|
pointer addresses. This is useful when diffing data structures in tests.
|
||||||
|
|
||||||
|
* DisableCapacities
|
||||||
|
DisableCapacities specifies whether to disable the printing of
|
||||||
|
capacities for arrays, slices, maps and channels. This is useful when
|
||||||
|
diffing data structures in tests.
|
||||||
|
|
||||||
|
* ContinueOnMethod
|
||||||
|
Enables recursion into types after invoking error and Stringer interface
|
||||||
|
methods. Recursion after method invocation is disabled by default.
|
||||||
|
|
||||||
|
* SortKeys
|
||||||
|
Specifies map keys should be sorted before being printed. Use
|
||||||
|
this to have a more deterministic, diffable output. Note that
|
||||||
|
only native types (bool, int, uint, floats, uintptr and string)
|
||||||
|
and types which implement error or Stringer interfaces are
|
||||||
|
supported with other types sorted according to the
|
||||||
|
reflect.Value.String() output which guarantees display
|
||||||
|
stability. Natural map order is used by default.
|
||||||
|
|
||||||
|
* SpewKeys
|
||||||
|
Specifies that, as a last resort attempt, map keys should be
|
||||||
|
spewed to strings and sorted by those strings. This is only
|
||||||
|
considered if SortKeys is true.
|
||||||
|
|
||||||
|
Dump Usage
|
||||||
|
|
||||||
|
Simply call spew.Dump with a list of variables you want to dump:
|
||||||
|
|
||||||
|
spew.Dump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
You may also call spew.Fdump if you would prefer to output to an arbitrary
|
||||||
|
io.Writer. For example, to dump to standard error:
|
||||||
|
|
||||||
|
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
A third option is to call spew.Sdump to get the formatted output as a string:
|
||||||
|
|
||||||
|
str := spew.Sdump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
Sample Dump Output
|
||||||
|
|
||||||
|
See the Dump example for details on the setup of the types and variables being
|
||||||
|
shown here.
|
||||||
|
|
||||||
|
(main.Foo) {
|
||||||
|
unexportedField: (*main.Bar)(0xf84002e210)({
|
||||||
|
flag: (main.Flag) flagTwo,
|
||||||
|
data: (uintptr) <nil>
|
||||||
|
}),
|
||||||
|
ExportedField: (map[interface {}]interface {}) (len=1) {
|
||||||
|
(string) (len=3) "one": (bool) true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
|
||||||
|
command as shown.
|
||||||
|
([]uint8) (len=32 cap=32) {
|
||||||
|
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
||||||
|
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
||||||
|
00000020 31 32 |12|
|
||||||
|
}
|
||||||
|
|
||||||
|
Custom Formatter
|
||||||
|
|
||||||
|
Spew provides a custom formatter that implements the fmt.Formatter interface
|
||||||
|
so that it integrates cleanly with standard fmt package printing functions. The
|
||||||
|
formatter is useful for inline printing of smaller data types similar to the
|
||||||
|
standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Custom Formatter Usage
|
||||||
|
|
||||||
|
The simplest way to make use of the spew custom formatter is to call one of the
|
||||||
|
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
|
||||||
|
functions have syntax you are most likely already familiar with:
|
||||||
|
|
||||||
|
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
spew.Println(myVar, myVar2)
|
||||||
|
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
|
||||||
|
See the Index for the full list convenience functions.
|
||||||
|
|
||||||
|
Sample Formatter Output
|
||||||
|
|
||||||
|
Double pointer to a uint8:
|
||||||
|
%v: <**>5
|
||||||
|
%+v: <**>(0xf8400420d0->0xf8400420c8)5
|
||||||
|
%#v: (**uint8)5
|
||||||
|
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
|
||||||
|
|
||||||
|
Pointer to circular struct with a uint8 field and a pointer to itself:
|
||||||
|
%v: <*>{1 <*><shown>}
|
||||||
|
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
|
||||||
|
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
|
||||||
|
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
|
||||||
|
|
||||||
|
See the Printf example for details on the setup of variables being shown
|
||||||
|
here.
|
||||||
|
|
||||||
|
Errors
|
||||||
|
|
||||||
|
Since it is possible for custom Stringer/error interfaces to panic, spew
|
||||||
|
detects them and handles them internally by printing the panic information
|
||||||
|
inline with the output. Since spew is intended to provide deep pretty printing
|
||||||
|
capabilities on structures, it intentionally does not return any errors.
|
||||||
|
*/
|
||||||
|
package spew
|
509
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
Normal file
509
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
Normal file
|
@ -0,0 +1,509 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// uint8Type is a reflect.Type representing a uint8. It is used to
|
||||||
|
// convert cgo types to uint8 slices for hexdumping.
|
||||||
|
uint8Type = reflect.TypeOf(uint8(0))
|
||||||
|
|
||||||
|
// cCharRE is a regular expression that matches a cgo char.
|
||||||
|
// It is used to detect character arrays to hexdump them.
|
||||||
|
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
|
||||||
|
|
||||||
|
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
||||||
|
// char. It is used to detect unsigned character arrays to hexdump
|
||||||
|
// them.
|
||||||
|
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
|
||||||
|
|
||||||
|
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
||||||
|
// It is used to detect uint8_t arrays to hexdump them.
|
||||||
|
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// dumpState contains information about the state of a dump operation.
|
||||||
|
type dumpState struct {
|
||||||
|
w io.Writer
|
||||||
|
depth int
|
||||||
|
pointers map[uintptr]int
|
||||||
|
ignoreNextType bool
|
||||||
|
ignoreNextIndent bool
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// indent performs indentation according to the depth level and cs.Indent
|
||||||
|
// option.
|
||||||
|
func (d *dumpState) indent() {
|
||||||
|
if d.ignoreNextIndent {
|
||||||
|
d.ignoreNextIndent = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpackValue returns values inside of non-nil interfaces when possible.
|
||||||
|
// This is useful for data types like structs, arrays, slices, and maps which
|
||||||
|
// can contain varying types packed inside an interface.
|
||||||
|
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
|
||||||
|
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpPtr handles formatting of pointers by indirecting them as necessary.
|
||||||
|
func (d *dumpState) dumpPtr(v reflect.Value) {
|
||||||
|
// Remove pointers at or below the current depth from map used to detect
|
||||||
|
// circular refs.
|
||||||
|
for k, depth := range d.pointers {
|
||||||
|
if depth >= d.depth {
|
||||||
|
delete(d.pointers, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep list of all dereferenced pointers to show later.
|
||||||
|
pointerChain := make([]uintptr, 0)
|
||||||
|
|
||||||
|
// Figure out how many levels of indirection there are by dereferencing
|
||||||
|
// pointers and unpacking interfaces down the chain while detecting circular
|
||||||
|
// references.
|
||||||
|
nilFound := false
|
||||||
|
cycleFound := false
|
||||||
|
indirects := 0
|
||||||
|
ve := v
|
||||||
|
for ve.Kind() == reflect.Ptr {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
indirects++
|
||||||
|
addr := ve.Pointer()
|
||||||
|
pointerChain = append(pointerChain, addr)
|
||||||
|
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
|
||||||
|
cycleFound = true
|
||||||
|
indirects--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
d.pointers[addr] = d.depth
|
||||||
|
|
||||||
|
ve = ve.Elem()
|
||||||
|
if ve.Kind() == reflect.Interface {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ve = ve.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display type information.
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
|
||||||
|
d.w.Write([]byte(ve.Type().String()))
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
|
||||||
|
// Display pointer information.
|
||||||
|
if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
for i, addr := range pointerChain {
|
||||||
|
if i > 0 {
|
||||||
|
d.w.Write(pointerChainBytes)
|
||||||
|
}
|
||||||
|
printHexPtr(d.w, addr)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display dereferenced value.
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
switch {
|
||||||
|
case nilFound:
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
|
||||||
|
case cycleFound:
|
||||||
|
d.w.Write(circularBytes)
|
||||||
|
|
||||||
|
default:
|
||||||
|
d.ignoreNextType = true
|
||||||
|
d.dump(ve)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
|
||||||
|
// reflection) arrays and slices are dumped in hexdump -C fashion.
|
||||||
|
func (d *dumpState) dumpSlice(v reflect.Value) {
|
||||||
|
// Determine whether this type should be hex dumped or not. Also,
|
||||||
|
// for types which should be hexdumped, try to use the underlying data
|
||||||
|
// first, then fall back to trying to convert them to a uint8 slice.
|
||||||
|
var buf []uint8
|
||||||
|
doConvert := false
|
||||||
|
doHexDump := false
|
||||||
|
numEntries := v.Len()
|
||||||
|
if numEntries > 0 {
|
||||||
|
vt := v.Index(0).Type()
|
||||||
|
vts := vt.String()
|
||||||
|
switch {
|
||||||
|
// C types that need to be converted.
|
||||||
|
case cCharRE.MatchString(vts):
|
||||||
|
fallthrough
|
||||||
|
case cUnsignedCharRE.MatchString(vts):
|
||||||
|
fallthrough
|
||||||
|
case cUint8tCharRE.MatchString(vts):
|
||||||
|
doConvert = true
|
||||||
|
|
||||||
|
// Try to use existing uint8 slices and fall back to converting
|
||||||
|
// and copying if that fails.
|
||||||
|
case vt.Kind() == reflect.Uint8:
|
||||||
|
// We need an addressable interface to convert the type
|
||||||
|
// to a byte slice. However, the reflect package won't
|
||||||
|
// give us an interface on certain things like
|
||||||
|
// unexported struct fields in order to enforce
|
||||||
|
// visibility rules. We use unsafe, when available, to
|
||||||
|
// bypass these restrictions since this package does not
|
||||||
|
// mutate the values.
|
||||||
|
vs := v
|
||||||
|
if !vs.CanInterface() || !vs.CanAddr() {
|
||||||
|
vs = unsafeReflectValue(vs)
|
||||||
|
}
|
||||||
|
if !UnsafeDisabled {
|
||||||
|
vs = vs.Slice(0, numEntries)
|
||||||
|
|
||||||
|
// Use the existing uint8 slice if it can be
|
||||||
|
// type asserted.
|
||||||
|
iface := vs.Interface()
|
||||||
|
if slice, ok := iface.([]uint8); ok {
|
||||||
|
buf = slice
|
||||||
|
doHexDump = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The underlying data needs to be converted if it can't
|
||||||
|
// be type asserted to a uint8 slice.
|
||||||
|
doConvert = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and convert the underlying type if needed.
|
||||||
|
if doConvert && vt.ConvertibleTo(uint8Type) {
|
||||||
|
// Convert and copy each element into a uint8 byte
|
||||||
|
// slice.
|
||||||
|
buf = make([]uint8, numEntries)
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
vv := v.Index(i)
|
||||||
|
buf[i] = uint8(vv.Convert(uint8Type).Uint())
|
||||||
|
}
|
||||||
|
doHexDump = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hexdump the entire slice as needed.
|
||||||
|
if doHexDump {
|
||||||
|
indent := strings.Repeat(d.cs.Indent, d.depth)
|
||||||
|
str := indent + hex.Dump(buf)
|
||||||
|
str = strings.Replace(str, "\n", "\n"+indent, -1)
|
||||||
|
str = strings.TrimRight(str, d.cs.Indent)
|
||||||
|
d.w.Write([]byte(str))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively call dump for each item.
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
d.dump(d.unpackValue(v.Index(i)))
|
||||||
|
if i < (numEntries - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
||||||
|
// value to figure out what kind of object we are dealing with and formats it
|
||||||
|
// appropriately. It is a recursive function, however circular data structures
|
||||||
|
// are detected and handled properly.
|
||||||
|
func (d *dumpState) dump(v reflect.Value) {
|
||||||
|
// Handle invalid reflect values immediately.
|
||||||
|
kind := v.Kind()
|
||||||
|
if kind == reflect.Invalid {
|
||||||
|
d.w.Write(invalidAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pointers specially.
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
d.indent()
|
||||||
|
d.dumpPtr(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print type information unless already handled elsewhere.
|
||||||
|
if !d.ignoreNextType {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
d.w.Write([]byte(v.Type().String()))
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
d.ignoreNextType = false
|
||||||
|
|
||||||
|
// Display length and capacity if the built-in len and cap functions
|
||||||
|
// work with the value's kind and the len/cap itself is non-zero.
|
||||||
|
valueLen, valueCap := 0, 0
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Array, reflect.Slice, reflect.Chan:
|
||||||
|
valueLen, valueCap = v.Len(), v.Cap()
|
||||||
|
case reflect.Map, reflect.String:
|
||||||
|
valueLen = v.Len()
|
||||||
|
}
|
||||||
|
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
if valueLen != 0 {
|
||||||
|
d.w.Write(lenEqualsBytes)
|
||||||
|
printInt(d.w, int64(valueLen), 10)
|
||||||
|
}
|
||||||
|
if !d.cs.DisableCapacities && valueCap != 0 {
|
||||||
|
if valueLen != 0 {
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
d.w.Write(capEqualsBytes)
|
||||||
|
printInt(d.w, int64(valueCap), 10)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call Stringer/error interfaces if they exist and the handle methods flag
|
||||||
|
// is enabled
|
||||||
|
if !d.cs.DisableMethods {
|
||||||
|
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||||
|
if handled := handleMethods(d.cs, d.w, v); handled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Invalid:
|
||||||
|
// Do nothing. We should never get here since invalid has already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
printBool(d.w, v.Bool())
|
||||||
|
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
printInt(d.w, v.Int(), 10)
|
||||||
|
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
printUint(d.w, v.Uint(), 10)
|
||||||
|
|
||||||
|
case reflect.Float32:
|
||||||
|
printFloat(d.w, v.Float(), 32)
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
printFloat(d.w, v.Float(), 64)
|
||||||
|
|
||||||
|
case reflect.Complex64:
|
||||||
|
printComplex(d.w, v.Complex(), 32)
|
||||||
|
|
||||||
|
case reflect.Complex128:
|
||||||
|
printComplex(d.w, v.Complex(), 64)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case reflect.Array:
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.dumpSlice(v)
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
d.w.Write([]byte(strconv.Quote(v.String())))
|
||||||
|
|
||||||
|
case reflect.Interface:
|
||||||
|
// The only time we should get here is for nil interfaces due to
|
||||||
|
// unpackValue calls.
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Do nothing. We should never get here since pointers have already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// nil maps should be indicated as different than empty maps
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
numEntries := v.Len()
|
||||||
|
keys := v.MapKeys()
|
||||||
|
if d.cs.SortKeys {
|
||||||
|
sortValues(keys, d.cs)
|
||||||
|
}
|
||||||
|
for i, key := range keys {
|
||||||
|
d.dump(d.unpackValue(key))
|
||||||
|
d.w.Write(colonSpaceBytes)
|
||||||
|
d.ignoreNextIndent = true
|
||||||
|
d.dump(d.unpackValue(v.MapIndex(key)))
|
||||||
|
if i < (numEntries - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
vt := v.Type()
|
||||||
|
numFields := v.NumField()
|
||||||
|
for i := 0; i < numFields; i++ {
|
||||||
|
d.indent()
|
||||||
|
vtf := vt.Field(i)
|
||||||
|
d.w.Write([]byte(vtf.Name))
|
||||||
|
d.w.Write(colonSpaceBytes)
|
||||||
|
d.ignoreNextIndent = true
|
||||||
|
d.dump(d.unpackValue(v.Field(i)))
|
||||||
|
if i < (numFields - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Uintptr:
|
||||||
|
printHexPtr(d.w, uintptr(v.Uint()))
|
||||||
|
|
||||||
|
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
||||||
|
printHexPtr(d.w, v.Pointer())
|
||||||
|
|
||||||
|
// There were not any other types at the time this code was written, but
|
||||||
|
// fall back to letting the default fmt package handle it in case any new
|
||||||
|
// types are added.
|
||||||
|
default:
|
||||||
|
if v.CanInterface() {
|
||||||
|
fmt.Fprintf(d.w, "%v", v.Interface())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(d.w, "%v", v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fdump is a helper function to consolidate the logic from the various public
|
||||||
|
// methods which take varying writers and config states.
|
||||||
|
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
|
||||||
|
for _, arg := range a {
|
||||||
|
if arg == nil {
|
||||||
|
w.Write(interfaceBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
w.Write(nilAngleBytes)
|
||||||
|
w.Write(newlineBytes)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
d := dumpState{w: w, cs: cs}
|
||||||
|
d.pointers = make(map[uintptr]int)
|
||||||
|
d.dump(reflect.ValueOf(arg))
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
fdump(&Config, w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sdump returns a string with the passed arguments formatted exactly the same
|
||||||
|
// as Dump.
|
||||||
|
func Sdump(a ...interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fdump(&Config, &buf, a...)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
|
indentation, and additional debug information such as complete types and all
|
||||||
|
pointer addresses used to indirect to the final value. It provides the
|
||||||
|
following features over the built-in printing facilities provided by the fmt
|
||||||
|
package:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
|
The configuration options are controlled by an exported package global,
|
||||||
|
spew.Config. See ConfigState for options documentation.
|
||||||
|
|
||||||
|
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
||||||
|
get the formatted result as a string.
|
||||||
|
*/
|
||||||
|
func Dump(a ...interface{}) {
|
||||||
|
fdump(&Config, os.Stdout, a...)
|
||||||
|
}
|
419
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
Normal file
419
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// supportedFlags is a list of all the character flags supported by fmt package.
|
||||||
|
const supportedFlags = "0-+# "
|
||||||
|
|
||||||
|
// formatState implements the fmt.Formatter interface and contains information
|
||||||
|
// about the state of a formatting operation. The NewFormatter function can
|
||||||
|
// be used to get a new Formatter which can be used directly as arguments
|
||||||
|
// in standard fmt package printing calls.
|
||||||
|
type formatState struct {
|
||||||
|
value interface{}
|
||||||
|
fs fmt.State
|
||||||
|
depth int
|
||||||
|
pointers map[uintptr]int
|
||||||
|
ignoreNextType bool
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildDefaultFormat recreates the original format string without precision
|
||||||
|
// and width information to pass in to fmt.Sprintf in the case of an
|
||||||
|
// unrecognized type. Unless new types are added to the language, this
|
||||||
|
// function won't ever be called.
|
||||||
|
func (f *formatState) buildDefaultFormat() (format string) {
|
||||||
|
buf := bytes.NewBuffer(percentBytes)
|
||||||
|
|
||||||
|
for _, flag := range supportedFlags {
|
||||||
|
if f.fs.Flag(int(flag)) {
|
||||||
|
buf.WriteRune(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteRune('v')
|
||||||
|
|
||||||
|
format = buf.String()
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructOrigFormat recreates the original format string including precision
|
||||||
|
// and width information to pass along to the standard fmt package. This allows
|
||||||
|
// automatic deferral of all format strings this package doesn't support.
|
||||||
|
func (f *formatState) constructOrigFormat(verb rune) (format string) {
|
||||||
|
buf := bytes.NewBuffer(percentBytes)
|
||||||
|
|
||||||
|
for _, flag := range supportedFlags {
|
||||||
|
if f.fs.Flag(int(flag)) {
|
||||||
|
buf.WriteRune(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if width, ok := f.fs.Width(); ok {
|
||||||
|
buf.WriteString(strconv.Itoa(width))
|
||||||
|
}
|
||||||
|
|
||||||
|
if precision, ok := f.fs.Precision(); ok {
|
||||||
|
buf.Write(precisionBytes)
|
||||||
|
buf.WriteString(strconv.Itoa(precision))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteRune(verb)
|
||||||
|
|
||||||
|
format = buf.String()
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpackValue returns values inside of non-nil interfaces when possible and
|
||||||
|
// ensures that types for values which have been unpacked from an interface
|
||||||
|
// are displayed when the show types flag is also set.
|
||||||
|
// This is useful for data types like structs, arrays, slices, and maps which
|
||||||
|
// can contain varying types packed inside an interface.
|
||||||
|
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
|
||||||
|
if v.Kind() == reflect.Interface {
|
||||||
|
f.ignoreNextType = false
|
||||||
|
if !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatPtr handles formatting of pointers by indirecting them as necessary.
|
||||||
|
func (f *formatState) formatPtr(v reflect.Value) {
|
||||||
|
// Display nil if top level pointer is nil.
|
||||||
|
showTypes := f.fs.Flag('#')
|
||||||
|
if v.IsNil() && (!showTypes || f.ignoreNextType) {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove pointers at or below the current depth from map used to detect
|
||||||
|
// circular refs.
|
||||||
|
for k, depth := range f.pointers {
|
||||||
|
if depth >= f.depth {
|
||||||
|
delete(f.pointers, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep list of all dereferenced pointers to possibly show later.
|
||||||
|
pointerChain := make([]uintptr, 0)
|
||||||
|
|
||||||
|
// Figure out how many levels of indirection there are by derferencing
|
||||||
|
// pointers and unpacking interfaces down the chain while detecting circular
|
||||||
|
// references.
|
||||||
|
nilFound := false
|
||||||
|
cycleFound := false
|
||||||
|
indirects := 0
|
||||||
|
ve := v
|
||||||
|
for ve.Kind() == reflect.Ptr {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
indirects++
|
||||||
|
addr := ve.Pointer()
|
||||||
|
pointerChain = append(pointerChain, addr)
|
||||||
|
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
|
||||||
|
cycleFound = true
|
||||||
|
indirects--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
f.pointers[addr] = f.depth
|
||||||
|
|
||||||
|
ve = ve.Elem()
|
||||||
|
if ve.Kind() == reflect.Interface {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ve = ve.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display type or indirection level depending on flags.
|
||||||
|
if showTypes && !f.ignoreNextType {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
|
||||||
|
f.fs.Write([]byte(ve.Type().String()))
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
} else {
|
||||||
|
if nilFound || cycleFound {
|
||||||
|
indirects += strings.Count(ve.Type().String(), "*")
|
||||||
|
}
|
||||||
|
f.fs.Write(openAngleBytes)
|
||||||
|
f.fs.Write([]byte(strings.Repeat("*", indirects)))
|
||||||
|
f.fs.Write(closeAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display pointer information depending on flags.
|
||||||
|
if f.fs.Flag('+') && (len(pointerChain) > 0) {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
for i, addr := range pointerChain {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(pointerChainBytes)
|
||||||
|
}
|
||||||
|
printHexPtr(f.fs, addr)
|
||||||
|
}
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display dereferenced value.
|
||||||
|
switch {
|
||||||
|
case nilFound:
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
|
||||||
|
case cycleFound:
|
||||||
|
f.fs.Write(circularShortBytes)
|
||||||
|
|
||||||
|
default:
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(ve)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// format is the main workhorse for providing the Formatter interface. It
|
||||||
|
// uses the passed reflect value to figure out what kind of object we are
|
||||||
|
// dealing with and formats it appropriately. It is a recursive function,
|
||||||
|
// however circular data structures are detected and handled properly.
|
||||||
|
func (f *formatState) format(v reflect.Value) {
|
||||||
|
// Handle invalid reflect values immediately.
|
||||||
|
kind := v.Kind()
|
||||||
|
if kind == reflect.Invalid {
|
||||||
|
f.fs.Write(invalidAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pointers specially.
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
f.formatPtr(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print type information unless already handled elsewhere.
|
||||||
|
if !f.ignoreNextType && f.fs.Flag('#') {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
f.fs.Write([]byte(v.Type().String()))
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = false
|
||||||
|
|
||||||
|
// Call Stringer/error interfaces if they exist and the handle methods
|
||||||
|
// flag is enabled.
|
||||||
|
if !f.cs.DisableMethods {
|
||||||
|
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||||
|
if handled := handleMethods(f.cs, f.fs, v); handled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Invalid:
|
||||||
|
// Do nothing. We should never get here since invalid has already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
printBool(f.fs, v.Bool())
|
||||||
|
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
printInt(f.fs, v.Int(), 10)
|
||||||
|
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
printUint(f.fs, v.Uint(), 10)
|
||||||
|
|
||||||
|
case reflect.Float32:
|
||||||
|
printFloat(f.fs, v.Float(), 32)
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
printFloat(f.fs, v.Float(), 64)
|
||||||
|
|
||||||
|
case reflect.Complex64:
|
||||||
|
printComplex(f.fs, v.Complex(), 32)
|
||||||
|
|
||||||
|
case reflect.Complex128:
|
||||||
|
printComplex(f.fs, v.Complex(), 64)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case reflect.Array:
|
||||||
|
f.fs.Write(openBracketBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
numEntries := v.Len()
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(v.Index(i)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeBracketBytes)
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
f.fs.Write([]byte(v.String()))
|
||||||
|
|
||||||
|
case reflect.Interface:
|
||||||
|
// The only time we should get here is for nil interfaces due to
|
||||||
|
// unpackValue calls.
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Do nothing. We should never get here since pointers have already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// nil maps should be indicated as different than empty maps
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
f.fs.Write(openMapBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
keys := v.MapKeys()
|
||||||
|
if f.cs.SortKeys {
|
||||||
|
sortValues(keys, f.cs)
|
||||||
|
}
|
||||||
|
for i, key := range keys {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(key))
|
||||||
|
f.fs.Write(colonBytes)
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(v.MapIndex(key)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeMapBytes)
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
numFields := v.NumField()
|
||||||
|
f.fs.Write(openBraceBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
vt := v.Type()
|
||||||
|
for i := 0; i < numFields; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
vtf := vt.Field(i)
|
||||||
|
if f.fs.Flag('+') || f.fs.Flag('#') {
|
||||||
|
f.fs.Write([]byte(vtf.Name))
|
||||||
|
f.fs.Write(colonBytes)
|
||||||
|
}
|
||||||
|
f.format(f.unpackValue(v.Field(i)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Uintptr:
|
||||||
|
printHexPtr(f.fs, uintptr(v.Uint()))
|
||||||
|
|
||||||
|
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
||||||
|
printHexPtr(f.fs, v.Pointer())
|
||||||
|
|
||||||
|
// There were not any other types at the time this code was written, but
|
||||||
|
// fall back to letting the default fmt package handle it if any get added.
|
||||||
|
default:
|
||||||
|
format := f.buildDefaultFormat()
|
||||||
|
if v.CanInterface() {
|
||||||
|
fmt.Fprintf(f.fs, format, v.Interface())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(f.fs, format, v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
|
||||||
|
// details.
|
||||||
|
func (f *formatState) Format(fs fmt.State, verb rune) {
|
||||||
|
f.fs = fs
|
||||||
|
|
||||||
|
// Use standard formatting for verbs that are not v.
|
||||||
|
if verb != 'v' {
|
||||||
|
format := f.constructOrigFormat(verb)
|
||||||
|
fmt.Fprintf(fs, format, f.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.value == nil {
|
||||||
|
if fs.Flag('#') {
|
||||||
|
fs.Write(interfaceBytes)
|
||||||
|
}
|
||||||
|
fs.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.format(reflect.ValueOf(f.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// newFormatter is a helper function to consolidate the logic from the various
|
||||||
|
// public methods which take varying config states.
|
||||||
|
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
|
||||||
|
fs := &formatState{value: v, cs: cs}
|
||||||
|
fs.pointers = make(map[uintptr]int)
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
printing functions. The formatter is useful for inline printing of smaller data
|
||||||
|
types similar to the standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Typically this function shouldn't be called directly. It is much easier to make
|
||||||
|
use of the custom formatter by calling one of the convenience functions such as
|
||||||
|
Printf, Println, or Fprintf.
|
||||||
|
*/
|
||||||
|
func NewFormatter(v interface{}) fmt.Formatter {
|
||||||
|
return newFormatter(&Config, v)
|
||||||
|
}
|
148
vendor/github.com/davecgh/go-spew/spew/spew.go
generated
vendored
Normal file
148
vendor/github.com/davecgh/go-spew/spew/spew.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the formatted string as a value that satisfies error. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Errorf(format string, a ...interface{}) (err error) {
|
||||||
|
return fmt.Errorf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprint(w, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintf(w, format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintln(w, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Print(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Print(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Printf(format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Printf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Println(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Println(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprint(a ...interface{}) string {
|
||||||
|
return fmt.Sprint(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprintf(format string, a ...interface{}) string {
|
||||||
|
return fmt.Sprintf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
||||||
|
// were passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprintln(a ...interface{}) string {
|
||||||
|
return fmt.Sprintln(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgs accepts a slice of arguments and returns a slice of the same
|
||||||
|
// length with each argument converted to a default spew Formatter interface.
|
||||||
|
func convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
|
formatters = make([]interface{}, len(args))
|
||||||
|
for index, arg := range args {
|
||||||
|
formatters[index] = NewFormatter(arg)
|
||||||
|
}
|
||||||
|
return formatters
|
||||||
|
}
|
4
vendor/github.com/mattn/go-sqlite3/.codecov.yml
generated
vendored
Normal file
4
vendor/github.com/mattn/go-sqlite3/.codecov.yml
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project: off
|
||||||
|
patch: off
|
14
vendor/github.com/mattn/go-sqlite3/.gitignore
generated
vendored
Normal file
14
vendor/github.com/mattn/go-sqlite3/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
*.db
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.o
|
||||||
|
|
||||||
|
# VSCode
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
# Exclude from upgrade
|
||||||
|
upgrade/*.c
|
||||||
|
upgrade/*.h
|
||||||
|
|
||||||
|
# Exclude upgrade binary
|
||||||
|
upgrade/upgrade
|
21
vendor/github.com/mattn/go-sqlite3/LICENSE
generated
vendored
Normal file
21
vendor/github.com/mattn/go-sqlite3/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Yasuhiro Matsumoto
|
||||||
|
|
||||||
|
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.
|
592
vendor/github.com/mattn/go-sqlite3/README.md
generated
vendored
Normal file
592
vendor/github.com/mattn/go-sqlite3/README.md
generated
vendored
Normal file
|
@ -0,0 +1,592 @@
|
||||||
|
go-sqlite3
|
||||||
|
==========
|
||||||
|
|
||||||
|
[![GoDoc Reference](https://godoc.org/github.com/mattn/go-sqlite3?status.svg)](http://godoc.org/github.com/mattn/go-sqlite3)
|
||||||
|
[![GitHub Actions](https://github.com/mattn/go-sqlite3/workflows/Go/badge.svg)](https://github.com/mattn/go-sqlite3/actions?query=workflow%3AGo)
|
||||||
|
[![Financial Contributors on Open Collective](https://opencollective.com/mattn-go-sqlite3/all/badge.svg?label=financial+contributors)](https://opencollective.com/mattn-go-sqlite3)
|
||||||
|
[![codecov](https://codecov.io/gh/mattn/go-sqlite3/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-sqlite3)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-sqlite3)](https://goreportcard.com/report/github.com/mattn/go-sqlite3)
|
||||||
|
|
||||||
|
Latest stable version is v1.14 or later not v2.
|
||||||
|
|
||||||
|
~~**NOTE:** The increase to v2 was an accident. There were no major changes or features.~~
|
||||||
|
|
||||||
|
# Description
|
||||||
|
|
||||||
|
sqlite3 driver conforming to the built-in database/sql interface
|
||||||
|
|
||||||
|
Supported Golang version: See [.github/workflows/go.yaml](./.github/workflows/go.yaml)
|
||||||
|
|
||||||
|
[This package follows the official Golang Release Policy.](https://golang.org/doc/devel/release.html#policy)
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
- [go-sqlite3](#go-sqlite3)
|
||||||
|
- [Description](#description)
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [API Reference](#api-reference)
|
||||||
|
- [Connection String](#connection-string)
|
||||||
|
- [DSN Examples](#dsn-examples)
|
||||||
|
- [Features](#features)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Feature / Extension List](#feature--extension-list)
|
||||||
|
- [Compilation](#compilation)
|
||||||
|
- [Android](#android)
|
||||||
|
- [ARM](#arm)
|
||||||
|
- [Cross Compile](#cross-compile)
|
||||||
|
- [Google Cloud Platform](#google-cloud-platform)
|
||||||
|
- [Linux](#linux)
|
||||||
|
- [Alpine](#alpine)
|
||||||
|
- [Fedora](#fedora)
|
||||||
|
- [Ubuntu](#ubuntu)
|
||||||
|
- [Mac OSX](#mac-osx)
|
||||||
|
- [Windows](#windows)
|
||||||
|
- [Errors](#errors)
|
||||||
|
- [User Authentication](#user-authentication)
|
||||||
|
- [Compile](#compile)
|
||||||
|
- [Usage](#usage-1)
|
||||||
|
- [Create protected database](#create-protected-database)
|
||||||
|
- [Password Encoding](#password-encoding)
|
||||||
|
- [Available Encoders](#available-encoders)
|
||||||
|
- [Restrictions](#restrictions)
|
||||||
|
- [Support](#support)
|
||||||
|
- [User Management](#user-management)
|
||||||
|
- [SQL](#sql)
|
||||||
|
- [Examples](#examples)
|
||||||
|
- [*SQLiteConn](#sqliteconn)
|
||||||
|
- [Attached database](#attached-database)
|
||||||
|
- [Extensions](#extensions)
|
||||||
|
- [Spatialite](#spatialite)
|
||||||
|
- [FAQ](#faq)
|
||||||
|
- [License](#license)
|
||||||
|
- [Author](#author)
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
This package can be installed with the go get command:
|
||||||
|
|
||||||
|
go get github.com/mattn/go-sqlite3
|
||||||
|
|
||||||
|
_go-sqlite3_ is *cgo* package.
|
||||||
|
If you want to build your app using go-sqlite3, you need gcc.
|
||||||
|
However, after you have built and installed _go-sqlite3_ with `go install github.com/mattn/go-sqlite3` (which requires gcc), you can build your app without relying on gcc in future.
|
||||||
|
|
||||||
|
***Important: because this is a `CGO` enabled package you are required to set the environment variable `CGO_ENABLED=1` and have a `gcc` compile present within your path.***
|
||||||
|
|
||||||
|
# API Reference
|
||||||
|
|
||||||
|
API documentation can be found here: http://godoc.org/github.com/mattn/go-sqlite3
|
||||||
|
|
||||||
|
Examples can be found under the [examples](./_example) directory
|
||||||
|
|
||||||
|
# Connection String
|
||||||
|
|
||||||
|
When creating a new SQLite database or connection to an existing one, with the file name additional options can be given.
|
||||||
|
This is also known as a DSN string. (Data Source Name).
|
||||||
|
|
||||||
|
Options are append after the filename of the SQLite database.
|
||||||
|
The database filename and options are seperated by an `?` (Question Mark).
|
||||||
|
Options should be URL-encoded (see [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)).
|
||||||
|
|
||||||
|
This also applies when using an in-memory database instead of a file.
|
||||||
|
|
||||||
|
Options can be given using the following format: `KEYWORD=VALUE` and multiple options can be combined with the `&` ampersand.
|
||||||
|
|
||||||
|
This library supports dsn options of SQLite itself and provides additional options.
|
||||||
|
|
||||||
|
Boolean values can be one of:
|
||||||
|
* `0` `no` `false` `off`
|
||||||
|
* `1` `yes` `true` `on`
|
||||||
|
|
||||||
|
| Name | Key | Value(s) | Description |
|
||||||
|
|------|-----|----------|-------------|
|
||||||
|
| UA - Create | `_auth` | - | Create User Authentication, for more information see [User Authentication](#user-authentication) |
|
||||||
|
| UA - Username | `_auth_user` | `string` | Username for User Authentication, for more information see [User Authentication](#user-authentication) |
|
||||||
|
| UA - Password | `_auth_pass` | `string` | Password for User Authentication, for more information see [User Authentication](#user-authentication) |
|
||||||
|
| UA - Crypt | `_auth_crypt` | <ul><li>SHA1</li><li>SSHA1</li><li>SHA256</li><li>SSHA256</li><li>SHA384</li><li>SSHA384</li><li>SHA512</li><li>SSHA512</li></ul> | Password encoder to use for User Authentication, for more information see [User Authentication](#user-authentication) |
|
||||||
|
| UA - Salt | `_auth_salt` | `string` | Salt to use if the configure password encoder requires a salt, for User Authentication, for more information see [User Authentication](#user-authentication) |
|
||||||
|
| Auto Vacuum | `_auto_vacuum` \| `_vacuum` | <ul><li>`0` \| `none`</li><li>`1` \| `full`</li><li>`2` \| `incremental`</li></ul> | For more information see [PRAGMA auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) |
|
||||||
|
| Busy Timeout | `_busy_timeout` \| `_timeout` | `int` | Specify value for sqlite3_busy_timeout. For more information see [PRAGMA busy_timeout](https://www.sqlite.org/pragma.html#pragma_busy_timeout) |
|
||||||
|
| Case Sensitive LIKE | `_case_sensitive_like` \| `_cslike` | `boolean` | For more information see [PRAGMA case_sensitive_like](https://www.sqlite.org/pragma.html#pragma_case_sensitive_like) |
|
||||||
|
| Defer Foreign Keys | `_defer_foreign_keys` \| `_defer_fk` | `boolean` | For more information see [PRAGMA defer_foreign_keys](https://www.sqlite.org/pragma.html#pragma_defer_foreign_keys) |
|
||||||
|
| Foreign Keys | `_foreign_keys` \| `_fk` | `boolean` | For more information see [PRAGMA foreign_keys](https://www.sqlite.org/pragma.html#pragma_foreign_keys) |
|
||||||
|
| Ignore CHECK Constraints | `_ignore_check_constraints` | `boolean` | For more information see [PRAGMA ignore_check_constraints](https://www.sqlite.org/pragma.html#pragma_ignore_check_constraints) |
|
||||||
|
| Immutable | `immutable` | `boolean` | For more information see [Immutable](https://www.sqlite.org/c3ref/open.html) |
|
||||||
|
| Journal Mode | `_journal_mode` \| `_journal` | <ul><li>DELETE</li><li>TRUNCATE</li><li>PERSIST</li><li>MEMORY</li><li>WAL</li><li>OFF</li></ul> | For more information see [PRAGMA journal_mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) |
|
||||||
|
| Locking Mode | `_locking_mode` \| `_locking` | <ul><li>NORMAL</li><li>EXCLUSIVE</li></ul> | For more information see [PRAGMA locking_mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) |
|
||||||
|
| Mode | `mode` | <ul><li>ro</li><li>rw</li><li>rwc</li><li>memory</li></ul> | Access Mode of the database. For more information see [SQLite Open](https://www.sqlite.org/c3ref/open.html) |
|
||||||
|
| Mutex Locking | `_mutex` | <ul><li>no</li><li>full</li></ul> | Specify mutex mode. |
|
||||||
|
| Query Only | `_query_only` | `boolean` | For more information see [PRAGMA query_only](https://www.sqlite.org/pragma.html#pragma_query_only) |
|
||||||
|
| Recursive Triggers | `_recursive_triggers` \| `_rt` | `boolean` | For more information see [PRAGMA recursive_triggers](https://www.sqlite.org/pragma.html#pragma_recursive_triggers) |
|
||||||
|
| Secure Delete | `_secure_delete` | `boolean` \| `FAST` | For more information see [PRAGMA secure_delete](https://www.sqlite.org/pragma.html#pragma_secure_delete) |
|
||||||
|
| Shared-Cache Mode | `cache` | <ul><li>shared</li><li>private</li></ul> | Set cache mode for more information see [sqlite.org](https://www.sqlite.org/sharedcache.html) |
|
||||||
|
| Synchronous | `_synchronous` \| `_sync` | <ul><li>0 \| OFF</li><li>1 \| NORMAL</li><li>2 \| FULL</li><li>3 \| EXTRA</li></ul> | For more information see [PRAGMA synchronous](https://www.sqlite.org/pragma.html#pragma_synchronous) |
|
||||||
|
| Time Zone Location | `_loc` | auto | Specify location of time format. |
|
||||||
|
| Transaction Lock | `_txlock` | <ul><li>immediate</li><li>deferred</li><li>exclusive</li></ul> | Specify locking behavior for transactions. |
|
||||||
|
| Writable Schema | `_writable_schema` | `Boolean` | When this pragma is on, the SQLITE_MASTER tables in which database can be changed using ordinary UPDATE, INSERT, and DELETE statements. Warning: misuse of this pragma can easily result in a corrupt database file. |
|
||||||
|
| Cache Size | `_cache_size` | `int` | Maximum cache size; default is 2000K (2M). See [PRAGMA cache_size](https://sqlite.org/pragma.html#pragma_cache_size) |
|
||||||
|
|
||||||
|
|
||||||
|
## DSN Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
file:test.db?cache=shared&mode=memory
|
||||||
|
```
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
This package allows additional configuration of features available within SQLite3 to be enabled or disabled by golang build constraints also known as build `tags`.
|
||||||
|
|
||||||
|
[Click here for more information about build tags / constraints.](https://golang.org/pkg/go/build/#hdr-Build_Constraints)
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
If you wish to build this library with additional extensions / features.
|
||||||
|
Use the following command.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build --tags "<FEATURE>"
|
||||||
|
```
|
||||||
|
|
||||||
|
For available features see the extension list.
|
||||||
|
When using multiple build tags, all the different tags should be space delimted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build --tags "icu json1 fts5 secure_delete"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Feature / Extension List
|
||||||
|
|
||||||
|
| Extension | Build Tag | Description |
|
||||||
|
|-----------|-----------|-------------|
|
||||||
|
| Additional Statistics | sqlite_stat4 | This option adds additional logic to the ANALYZE command and to the query planner that can help SQLite to chose a better query plan under certain situations. The ANALYZE command is enhanced to collect histogram data from all columns of every index and store that data in the sqlite_stat4 table.<br><br>The query planner will then use the histogram data to help it make better index choices. The downside of this compile-time option is that it violates the query planner stability guarantee making it more difficult to ensure consistent performance in mass-produced applications.<br><br>SQLITE_ENABLE_STAT4 is an enhancement of SQLITE_ENABLE_STAT3. STAT3 only recorded histogram data for the left-most column of each index whereas the STAT4 enhancement records histogram data from all columns of each index.<br><br>The SQLITE_ENABLE_STAT3 compile-time option is a no-op and is ignored if the SQLITE_ENABLE_STAT4 compile-time option is used |
|
||||||
|
| Allow URI Authority | sqlite_allow_uri_authority | URI filenames normally throws an error if the authority section is not either empty or "localhost".<br><br>However, if SQLite is compiled with the SQLITE_ALLOW_URI_AUTHORITY compile-time option, then the URI is converted into a Uniform Naming Convention (UNC) filename and passed down to the underlying operating system that way |
|
||||||
|
| App Armor | sqlite_app_armor | When defined, this C-preprocessor macro activates extra code that attempts to detect misuse of the SQLite API, such as passing in NULL pointers to required parameters or using objects after they have been destroyed. <br><br>App Armor is not available under `Windows`. |
|
||||||
|
| Disable Load Extensions | sqlite_omit_load_extension | Loading of external extensions is enabled by default.<br><br>To disable extension loading add the build tag `sqlite_omit_load_extension`. |
|
||||||
|
| Foreign Keys | sqlite_foreign_keys | This macro determines whether enforcement of foreign key constraints is enabled or disabled by default for new database connections.<br><br>Each database connection can always turn enforcement of foreign key constraints on and off and run-time using the foreign_keys pragma.<br><br>Enforcement of foreign key constraints is normally off by default, but if this compile-time parameter is set to 1, enforcement of foreign key constraints will be on by default |
|
||||||
|
| Full Auto Vacuum | sqlite_vacuum_full | Set the default auto vacuum to full |
|
||||||
|
| Incremental Auto Vacuum | sqlite_vacuum_incr | Set the default auto vacuum to incremental |
|
||||||
|
| Full Text Search Engine | sqlite_fts5 | When this option is defined in the amalgamation, versions 5 of the full-text search engine (fts5) is added to the build automatically |
|
||||||
|
| International Components for Unicode | sqlite_icu | This option causes the International Components for Unicode or "ICU" extension to SQLite to be added to the build |
|
||||||
|
| Introspect PRAGMAS | sqlite_introspect | This option adds some extra PRAGMA statements. <ul><li>PRAGMA function_list</li><li>PRAGMA module_list</li><li>PRAGMA pragma_list</li></ul> |
|
||||||
|
| JSON SQL Functions | sqlite_json | When this option is defined in the amalgamation, the JSON SQL functions are added to the build automatically |
|
||||||
|
| Pre Update Hook | sqlite_preupdate_hook | Registers a callback function that is invoked prior to each INSERT, UPDATE, and DELETE operation on a database table. |
|
||||||
|
| Secure Delete | sqlite_secure_delete | This compile-time option changes the default setting of the secure_delete pragma.<br><br>When this option is not used, secure_delete defaults to off. When this option is present, secure_delete defaults to on.<br><br>The secure_delete setting causes deleted content to be overwritten with zeros. There is a small performance penalty since additional I/O must occur.<br><br>On the other hand, secure_delete can prevent fragments of sensitive information from lingering in unused parts of the database file after it has been deleted. See the documentation on the secure_delete pragma for additional information |
|
||||||
|
| Secure Delete (FAST) | sqlite_secure_delete_fast | For more information see [PRAGMA secure_delete](https://www.sqlite.org/pragma.html#pragma_secure_delete) |
|
||||||
|
| Tracing / Debug | sqlite_trace | Activate trace functions |
|
||||||
|
| User Authentication | sqlite_userauth | SQLite User Authentication see [User Authentication](#user-authentication) for more information. |
|
||||||
|
|
||||||
|
# Compilation
|
||||||
|
|
||||||
|
This package requires `CGO_ENABLED=1` ennvironment variable if not set by default, and the presence of the `gcc` compiler.
|
||||||
|
|
||||||
|
If you need to add additional CFLAGS or LDFLAGS to the build command, and do not want to modify this package. Then this can be achieved by using the `CGO_CFLAGS` and `CGO_LDFLAGS` environment variables.
|
||||||
|
|
||||||
|
## Android
|
||||||
|
|
||||||
|
This package can be compiled for android.
|
||||||
|
Compile with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build --tags "android"
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information see [#201](https://github.com/mattn/go-sqlite3/issues/201)
|
||||||
|
|
||||||
|
# ARM
|
||||||
|
|
||||||
|
To compile for `ARM` use the following environment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
env CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ \
|
||||||
|
CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 \
|
||||||
|
go build -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional information:
|
||||||
|
- [#242](https://github.com/mattn/go-sqlite3/issues/242)
|
||||||
|
- [#504](https://github.com/mattn/go-sqlite3/issues/504)
|
||||||
|
|
||||||
|
# Cross Compile
|
||||||
|
|
||||||
|
This library can be cross-compiled.
|
||||||
|
|
||||||
|
In some cases you are required to the `CC` environment variable with the cross compiler.
|
||||||
|
|
||||||
|
## Cross Compiling from MAC OSX
|
||||||
|
The simplest way to cross compile from OSX is to use [xgo](https://github.com/karalabe/xgo).
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
- Install [xgo](https://github.com/karalabe/xgo) (`go get github.com/karalabe/xgo`).
|
||||||
|
- Ensure that your project is within your `GOPATH`.
|
||||||
|
- Run `xgo local/path/to/project`.
|
||||||
|
|
||||||
|
Please refer to the project's [README](https://github.com/karalabe/xgo/blob/master/README.md) for further information.
|
||||||
|
|
||||||
|
# Google Cloud Platform
|
||||||
|
|
||||||
|
Building on GCP is not possible because Google Cloud Platform does not allow `gcc` to be executed.
|
||||||
|
|
||||||
|
Please work only with compiled final binaries.
|
||||||
|
|
||||||
|
## Linux
|
||||||
|
|
||||||
|
To compile this package on Linux you must install the development tools for your linux distribution.
|
||||||
|
|
||||||
|
To compile under linux use the build tag `linux`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build --tags "linux"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to link directly to libsqlite3 then you can use the `libsqlite3` build tag.
|
||||||
|
|
||||||
|
```
|
||||||
|
go build --tags "libsqlite3 linux"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alpine
|
||||||
|
|
||||||
|
When building in an `alpine` container run the following command before building.
|
||||||
|
|
||||||
|
```
|
||||||
|
apk add --update gcc musl-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fedora
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo yum groupinstall "Development Tools" "Development Libraries"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ubuntu
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install build-essential
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mac OSX
|
||||||
|
|
||||||
|
OSX should have all the tools present to compile this package, if not install XCode this will add all the developers tools.
|
||||||
|
|
||||||
|
Required dependency
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install sqlite3
|
||||||
|
```
|
||||||
|
|
||||||
|
For OSX there is an additional package install which is required if you wish to build the `icu` extension.
|
||||||
|
|
||||||
|
This additional package can be installed with `homebrew`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew upgrade icu4c
|
||||||
|
```
|
||||||
|
|
||||||
|
To compile for Mac OSX.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build --tags "darwin"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to link directly to libsqlite3 then you can use the `libsqlite3` build tag.
|
||||||
|
|
||||||
|
```
|
||||||
|
go build --tags "libsqlite3 darwin"
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional information:
|
||||||
|
- [#206](https://github.com/mattn/go-sqlite3/issues/206)
|
||||||
|
- [#404](https://github.com/mattn/go-sqlite3/issues/404)
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
To compile this package on Windows OS you must have the `gcc` compiler installed.
|
||||||
|
|
||||||
|
1) Install a Windows `gcc` toolchain.
|
||||||
|
2) Add the `bin` folders to the Windows path if the installer did not do this by default.
|
||||||
|
3) Open a terminal for the TDM-GCC toolchain, can be found in the Windows Start menu.
|
||||||
|
4) Navigate to your project folder and run the `go build ...` command for this package.
|
||||||
|
|
||||||
|
For example the TDM-GCC Toolchain can be found [here](https://sourceforge.net/projects/tdm-gcc/).
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
- Compile error: `can not be used when making a shared object; recompile with -fPIC`
|
||||||
|
|
||||||
|
When receiving a compile time error referencing recompile with `-FPIC` then you
|
||||||
|
are probably using a hardend system.
|
||||||
|
|
||||||
|
You can compile the library on a hardend system with the following command.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -ldflags '-extldflags=-fno-PIC'
|
||||||
|
```
|
||||||
|
|
||||||
|
More details see [#120](https://github.com/mattn/go-sqlite3/issues/120)
|
||||||
|
|
||||||
|
- Can't build go-sqlite3 on windows 64bit.
|
||||||
|
|
||||||
|
> Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit.
|
||||||
|
> See: [#27](https://github.com/mattn/go-sqlite3/issues/27)
|
||||||
|
|
||||||
|
- `go get github.com/mattn/go-sqlite3` throws compilation error.
|
||||||
|
|
||||||
|
`gcc` throws: `internal compiler error`
|
||||||
|
|
||||||
|
Remove the download repository from your disk and try re-install with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install github.com/mattn/go-sqlite3
|
||||||
|
```
|
||||||
|
|
||||||
|
# User Authentication
|
||||||
|
|
||||||
|
This package supports the SQLite User Authentication module.
|
||||||
|
|
||||||
|
## Compile
|
||||||
|
|
||||||
|
To use the User authentication module the package has to be compiled with the tag `sqlite_userauth`. See [Features](#features).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Create protected database
|
||||||
|
|
||||||
|
To create a database protected by user authentication provide the following argument to the connection string `_auth`.
|
||||||
|
This will enable user authentication within the database. This option however requires two additional arguments:
|
||||||
|
|
||||||
|
- `_auth_user`
|
||||||
|
- `_auth_pass`
|
||||||
|
|
||||||
|
When `_auth` is present on the connection string user authentication will be enabled and the provided user will be created
|
||||||
|
as an `admin` user. After initial creation, the parameter `_auth` has no effect anymore and can be omitted from the connection string.
|
||||||
|
|
||||||
|
Example connection string:
|
||||||
|
|
||||||
|
Create an user authentication database with user `admin` and password `admin`.
|
||||||
|
|
||||||
|
`file:test.s3db?_auth&_auth_user=admin&_auth_pass=admin`
|
||||||
|
|
||||||
|
Create an user authentication database with user `admin` and password `admin` and use `SHA1` for the password encoding.
|
||||||
|
|
||||||
|
`file:test.s3db?_auth&_auth_user=admin&_auth_pass=admin&_auth_crypt=sha1`
|
||||||
|
|
||||||
|
### Password Encoding
|
||||||
|
|
||||||
|
The passwords within the user authentication module of SQLite are encoded with the SQLite function `sqlite_cryp`.
|
||||||
|
This function uses a ceasar-cypher which is quite insecure.
|
||||||
|
This library provides several additional password encoders which can be configured through the connection string.
|
||||||
|
|
||||||
|
The password cypher can be configured with the key `_auth_crypt`. And if the configured password encoder also requires an
|
||||||
|
salt this can be configured with `_auth_salt`.
|
||||||
|
|
||||||
|
#### Available Encoders
|
||||||
|
|
||||||
|
- SHA1
|
||||||
|
- SSHA1 (Salted SHA1)
|
||||||
|
- SHA256
|
||||||
|
- SSHA256 (salted SHA256)
|
||||||
|
- SHA384
|
||||||
|
- SSHA384 (salted SHA384)
|
||||||
|
- SHA512
|
||||||
|
- SSHA512 (salted SHA512)
|
||||||
|
|
||||||
|
### Restrictions
|
||||||
|
|
||||||
|
Operations on the database regarding to user management can only be preformed by an administrator user.
|
||||||
|
|
||||||
|
### Support
|
||||||
|
|
||||||
|
The user authentication supports two kinds of users
|
||||||
|
|
||||||
|
- administrators
|
||||||
|
- regular users
|
||||||
|
|
||||||
|
### User Management
|
||||||
|
|
||||||
|
User management can be done by directly using the `*SQLiteConn` or by SQL.
|
||||||
|
|
||||||
|
#### SQL
|
||||||
|
|
||||||
|
The following sql functions are available for user management.
|
||||||
|
|
||||||
|
| Function | Arguments | Description |
|
||||||
|
|----------|-----------|-------------|
|
||||||
|
| `authenticate` | username `string`, password `string` | Will authenticate an user, this is done by the connection; and should not be used manually. |
|
||||||
|
| `auth_user_add` | username `string`, password `string`, admin `int` | This function will add an user to the database.<br>if the database is not protected by user authentication it will enable it. Argument `admin` is an integer identifying if the added user should be an administrator. Only Administrators can add administrators. |
|
||||||
|
| `auth_user_change` | username `string`, password `string`, admin `int` | Function to modify an user. Users can change their own password, but only an administrator can change the administrator flag. |
|
||||||
|
| `authUserDelete` | username `string` | Delete an user from the database. Can only be used by an administrator. The current logged in administrator cannot be deleted. This is to make sure their is always an administrator remaining. |
|
||||||
|
|
||||||
|
These functions will return an integer.
|
||||||
|
|
||||||
|
- 0 (SQLITE_OK)
|
||||||
|
- 23 (SQLITE_AUTH) Failed to perform due to authentication or insufficient privileges
|
||||||
|
|
||||||
|
##### Examples
|
||||||
|
|
||||||
|
```sql
|
||||||
|
// Autheticate user
|
||||||
|
// Create Admin User
|
||||||
|
SELECT auth_user_add('admin2', 'admin2', 1);
|
||||||
|
|
||||||
|
// Change password for user
|
||||||
|
SELECT auth_user_change('user', 'userpassword', 0);
|
||||||
|
|
||||||
|
// Delete user
|
||||||
|
SELECT user_delete('user');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### *SQLiteConn
|
||||||
|
|
||||||
|
The following functions are available for User authentication from the `*SQLiteConn`.
|
||||||
|
|
||||||
|
| Function | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `Authenticate(username, password string) error` | Authenticate user |
|
||||||
|
| `AuthUserAdd(username, password string, admin bool) error` | Add user |
|
||||||
|
| `AuthUserChange(username, password string, admin bool) error` | Modify user |
|
||||||
|
| `AuthUserDelete(username string) error` | Delete user |
|
||||||
|
|
||||||
|
### Attached database
|
||||||
|
|
||||||
|
When using attached databases. SQLite will use the authentication from the `main` database for the attached database(s).
|
||||||
|
|
||||||
|
# Extensions
|
||||||
|
|
||||||
|
If you want your own extension to be listed here or you want to add a reference to an extension; please submit an Issue for this.
|
||||||
|
|
||||||
|
## Spatialite
|
||||||
|
|
||||||
|
Spatialite is available as an extension to SQLite, and can be used in combination with this repository.
|
||||||
|
For an example see [shaxbee/go-spatialite](https://github.com/shaxbee/go-spatialite).
|
||||||
|
|
||||||
|
## extension-functions.c from SQLite3 Contrib
|
||||||
|
|
||||||
|
extension-functions.c is available as an extension to SQLite, and provides the following functions:
|
||||||
|
|
||||||
|
- Math: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference, degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp, log, log10, power, sign, sqrt, square, ceil, floor, pi.
|
||||||
|
- String: replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim, replace, reverse, proper, padl, padr, padc, strfilter.
|
||||||
|
- Aggregate: stdev, variance, mode, median, lower_quartile, upper_quartile
|
||||||
|
|
||||||
|
For an example see [dinedal/go-sqlite3-extension-functions](https://github.com/dinedal/go-sqlite3-extension-functions).
|
||||||
|
|
||||||
|
# FAQ
|
||||||
|
|
||||||
|
- Getting insert error while query is opened.
|
||||||
|
|
||||||
|
> You can pass some arguments into the connection string, for example, a URI.
|
||||||
|
> See: [#39](https://github.com/mattn/go-sqlite3/issues/39)
|
||||||
|
|
||||||
|
- Do you want to cross compile? mingw on Linux or Mac?
|
||||||
|
|
||||||
|
> See: [#106](https://github.com/mattn/go-sqlite3/issues/106)
|
||||||
|
> See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html
|
||||||
|
|
||||||
|
- Want to get time.Time with current locale
|
||||||
|
|
||||||
|
Use `_loc=auto` in SQLite3 filename schema like `file:foo.db?_loc=auto`.
|
||||||
|
|
||||||
|
- Can I use this in multiple routines concurrently?
|
||||||
|
|
||||||
|
Yes for readonly. But, No for writable. See [#50](https://github.com/mattn/go-sqlite3/issues/50), [#51](https://github.com/mattn/go-sqlite3/issues/51), [#209](https://github.com/mattn/go-sqlite3/issues/209), [#274](https://github.com/mattn/go-sqlite3/issues/274).
|
||||||
|
|
||||||
|
- Why I'm getting `no such table` error?
|
||||||
|
|
||||||
|
Why is it racy if I use a `sql.Open("sqlite3", ":memory:")` database?
|
||||||
|
|
||||||
|
Each connection to `":memory:"` opens a brand new in-memory sql database, so if
|
||||||
|
the stdlib's sql engine happens to open another connection and you've only
|
||||||
|
specified `":memory:"`, that connection will see a brand new database. A
|
||||||
|
workaround is to use `"file::memory:?cache=shared"` (or `"file:foobar?mode=memory&cache=shared"`). Every
|
||||||
|
connection to this string will point to the same in-memory database.
|
||||||
|
|
||||||
|
Note that if the last database connection in the pool closes, the in-memory database is deleted. Make sure the [max idle connection limit](https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns) is > 0, and the [connection lifetime](https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime) is infinite.
|
||||||
|
|
||||||
|
For more information see
|
||||||
|
* [#204](https://github.com/mattn/go-sqlite3/issues/204)
|
||||||
|
* [#511](https://github.com/mattn/go-sqlite3/issues/511)
|
||||||
|
* https://www.sqlite.org/sharedcache.html#shared_cache_and_in_memory_databases
|
||||||
|
* https://www.sqlite.org/inmemorydb.html#sharedmemdb
|
||||||
|
|
||||||
|
- Reading from database with large amount of goroutines fails on OSX.
|
||||||
|
|
||||||
|
OS X limits OS-wide to not have more than 1000 files open simultaneously by default.
|
||||||
|
|
||||||
|
For more information see [#289](https://github.com/mattn/go-sqlite3/issues/289)
|
||||||
|
|
||||||
|
- Trying to execute a `.` (dot) command throws an error.
|
||||||
|
|
||||||
|
Error: `Error: near ".": syntax error`
|
||||||
|
Dot command are part of SQLite3 CLI not of this library.
|
||||||
|
|
||||||
|
You need to implement the feature or call the sqlite3 cli.
|
||||||
|
|
||||||
|
More information see [#305](https://github.com/mattn/go-sqlite3/issues/305)
|
||||||
|
|
||||||
|
- Error: `database is locked`
|
||||||
|
|
||||||
|
When you get a database is locked. Please use the following options.
|
||||||
|
|
||||||
|
Add to DSN: `cache=shared`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```go
|
||||||
|
db, err := sql.Open("sqlite3", "file:locked.sqlite?cache=shared")
|
||||||
|
```
|
||||||
|
|
||||||
|
Second please set the database connections of the SQL package to 1.
|
||||||
|
|
||||||
|
```go
|
||||||
|
db.SetMaxOpenConns(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
More information see [#209](https://github.com/mattn/go-sqlite3/issues/209)
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
### Code Contributors
|
||||||
|
|
||||||
|
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||||
|
<a href="https://github.com/mattn/go-sqlite3/graphs/contributors"><img src="https://opencollective.com/mattn-go-sqlite3/contributors.svg?width=890&button=false" /></a>
|
||||||
|
|
||||||
|
### Financial Contributors
|
||||||
|
|
||||||
|
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/mattn-go-sqlite3/contribute)]
|
||||||
|
|
||||||
|
#### Individuals
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3"><img src="https://opencollective.com/mattn-go-sqlite3/individuals.svg?width=890"></a>
|
||||||
|
|
||||||
|
#### Organizations
|
||||||
|
|
||||||
|
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/mattn-go-sqlite3/contribute)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/0/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/0/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/1/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/2/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/3/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/4/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/5/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/6/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/7/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/8/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/mattn-go-sqlite3/organization/9/website"><img src="https://opencollective.com/mattn-go-sqlite3/organization/9/avatar.svg"></a>
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
MIT: http://mattn.mit-license.org/2018
|
||||||
|
|
||||||
|
sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h
|
||||||
|
|
||||||
|
The -binding suffix was added to avoid build failures under gccgo.
|
||||||
|
|
||||||
|
In this repository, those files are an amalgamation of code that was copied from SQLite3. The license of that code is the same as the license of SQLite3.
|
||||||
|
|
||||||
|
# Author
|
||||||
|
|
||||||
|
Yasuhiro Matsumoto (a.k.a mattn)
|
||||||
|
|
||||||
|
G.J.R. Timmer
|
85
vendor/github.com/mattn/go-sqlite3/backup.go
generated
vendored
Normal file
85
vendor/github.com/mattn/go-sqlite3/backup.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SQLiteBackup implement interface of Backup.
|
||||||
|
type SQLiteBackup struct {
|
||||||
|
b *C.sqlite3_backup
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup make backup from src to dest.
|
||||||
|
func (destConn *SQLiteConn) Backup(dest string, srcConn *SQLiteConn, src string) (*SQLiteBackup, error) {
|
||||||
|
destptr := C.CString(dest)
|
||||||
|
defer C.free(unsafe.Pointer(destptr))
|
||||||
|
srcptr := C.CString(src)
|
||||||
|
defer C.free(unsafe.Pointer(srcptr))
|
||||||
|
|
||||||
|
if b := C.sqlite3_backup_init(destConn.db, destptr, srcConn.db, srcptr); b != nil {
|
||||||
|
bb := &SQLiteBackup{b: b}
|
||||||
|
runtime.SetFinalizer(bb, (*SQLiteBackup).Finish)
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
return nil, destConn.lastError()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step to backs up for one step. Calls the underlying `sqlite3_backup_step`
|
||||||
|
// function. This function returns a boolean indicating if the backup is done
|
||||||
|
// and an error signalling any other error. Done is returned if the underlying
|
||||||
|
// C function returns SQLITE_DONE (Code 101)
|
||||||
|
func (b *SQLiteBackup) Step(p int) (bool, error) {
|
||||||
|
ret := C.sqlite3_backup_step(b.b, C.int(p))
|
||||||
|
if ret == C.SQLITE_DONE {
|
||||||
|
return true, nil
|
||||||
|
} else if ret != 0 && ret != C.SQLITE_LOCKED && ret != C.SQLITE_BUSY {
|
||||||
|
return false, Error{Code: ErrNo(ret)}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remaining return whether have the rest for backup.
|
||||||
|
func (b *SQLiteBackup) Remaining() int {
|
||||||
|
return int(C.sqlite3_backup_remaining(b.b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageCount return count of pages.
|
||||||
|
func (b *SQLiteBackup) PageCount() int {
|
||||||
|
return int(C.sqlite3_backup_pagecount(b.b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish close backup.
|
||||||
|
func (b *SQLiteBackup) Finish() error {
|
||||||
|
return b.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close close backup.
|
||||||
|
func (b *SQLiteBackup) Close() error {
|
||||||
|
ret := C.sqlite3_backup_finish(b.b)
|
||||||
|
|
||||||
|
// sqlite3_backup_finish() never fails, it just returns the
|
||||||
|
// error code from previous operations, so clean up before
|
||||||
|
// checking and returning an error
|
||||||
|
b.b = nil
|
||||||
|
runtime.SetFinalizer(b, nil)
|
||||||
|
|
||||||
|
if ret != 0 {
|
||||||
|
return Error{Code: ErrNo(ret)}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
392
vendor/github.com/mattn/go-sqlite3/callback.go
generated
vendored
Normal file
392
vendor/github.com/mattn/go-sqlite3/callback.go
generated
vendored
Normal file
|
@ -0,0 +1,392 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
// You can't export a Go function to C and have definitions in the C
|
||||||
|
// preamble in the same file, so we have to have callbackTrampoline in
|
||||||
|
// its own file. Because we need a separate file anyway, the support
|
||||||
|
// code for SQLite custom functions is in here.
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
|
||||||
|
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//export callbackTrampoline
|
||||||
|
func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) {
|
||||||
|
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
|
||||||
|
fi := lookupHandle(C.sqlite3_user_data(ctx)).(*functionInfo)
|
||||||
|
fi.Call(ctx, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export stepTrampoline
|
||||||
|
func stepTrampoline(ctx *C.sqlite3_context, argc C.int, argv **C.sqlite3_value) {
|
||||||
|
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:int(argc):int(argc)]
|
||||||
|
ai := lookupHandle(C.sqlite3_user_data(ctx)).(*aggInfo)
|
||||||
|
ai.Step(ctx, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export doneTrampoline
|
||||||
|
func doneTrampoline(ctx *C.sqlite3_context) {
|
||||||
|
ai := lookupHandle(C.sqlite3_user_data(ctx)).(*aggInfo)
|
||||||
|
ai.Done(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export compareTrampoline
|
||||||
|
func compareTrampoline(handlePtr unsafe.Pointer, la C.int, a *C.char, lb C.int, b *C.char) C.int {
|
||||||
|
cmp := lookupHandle(handlePtr).(func(string, string) int)
|
||||||
|
return C.int(cmp(C.GoStringN(a, la), C.GoStringN(b, lb)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export commitHookTrampoline
|
||||||
|
func commitHookTrampoline(handle unsafe.Pointer) int {
|
||||||
|
callback := lookupHandle(handle).(func() int)
|
||||||
|
return callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
//export rollbackHookTrampoline
|
||||||
|
func rollbackHookTrampoline(handle unsafe.Pointer) {
|
||||||
|
callback := lookupHandle(handle).(func())
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
//export updateHookTrampoline
|
||||||
|
func updateHookTrampoline(handle unsafe.Pointer, op int, db *C.char, table *C.char, rowid int64) {
|
||||||
|
callback := lookupHandle(handle).(func(int, string, string, int64))
|
||||||
|
callback(op, C.GoString(db), C.GoString(table), rowid)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export authorizerTrampoline
|
||||||
|
func authorizerTrampoline(handle unsafe.Pointer, op int, arg1 *C.char, arg2 *C.char, arg3 *C.char) int {
|
||||||
|
callback := lookupHandle(handle).(func(int, string, string, string) int)
|
||||||
|
return callback(op, C.GoString(arg1), C.GoString(arg2), C.GoString(arg3))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export preUpdateHookTrampoline
|
||||||
|
func preUpdateHookTrampoline(handle unsafe.Pointer, dbHandle uintptr, op int, db *C.char, table *C.char, oldrowid int64, newrowid int64) {
|
||||||
|
hval := lookupHandleVal(handle)
|
||||||
|
data := SQLitePreUpdateData{
|
||||||
|
Conn: hval.db,
|
||||||
|
Op: op,
|
||||||
|
DatabaseName: C.GoString(db),
|
||||||
|
TableName: C.GoString(table),
|
||||||
|
OldRowID: oldrowid,
|
||||||
|
NewRowID: newrowid,
|
||||||
|
}
|
||||||
|
callback := hval.val.(func(SQLitePreUpdateData))
|
||||||
|
callback(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use handles to avoid passing Go pointers to C.
|
||||||
|
type handleVal struct {
|
||||||
|
db *SQLiteConn
|
||||||
|
val interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var handleLock sync.Mutex
|
||||||
|
var handleVals = make(map[unsafe.Pointer]handleVal)
|
||||||
|
|
||||||
|
func newHandle(db *SQLiteConn, v interface{}) unsafe.Pointer {
|
||||||
|
handleLock.Lock()
|
||||||
|
defer handleLock.Unlock()
|
||||||
|
val := handleVal{db: db, val: v}
|
||||||
|
var p unsafe.Pointer = C.malloc(C.size_t(1))
|
||||||
|
if p == nil {
|
||||||
|
panic("can't allocate 'cgo-pointer hack index pointer': ptr == nil")
|
||||||
|
}
|
||||||
|
handleVals[p] = val
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupHandleVal(handle unsafe.Pointer) handleVal {
|
||||||
|
handleLock.Lock()
|
||||||
|
defer handleLock.Unlock()
|
||||||
|
return handleVals[handle]
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupHandle(handle unsafe.Pointer) interface{} {
|
||||||
|
return lookupHandleVal(handle).val
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteHandles(db *SQLiteConn) {
|
||||||
|
handleLock.Lock()
|
||||||
|
defer handleLock.Unlock()
|
||||||
|
for handle, val := range handleVals {
|
||||||
|
if val.db == db {
|
||||||
|
delete(handleVals, handle)
|
||||||
|
C.free(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only here so that tests can refer to it.
|
||||||
|
type callbackArgRaw C.sqlite3_value
|
||||||
|
|
||||||
|
type callbackArgConverter func(*C.sqlite3_value) (reflect.Value, error)
|
||||||
|
|
||||||
|
type callbackArgCast struct {
|
||||||
|
f callbackArgConverter
|
||||||
|
typ reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c callbackArgCast) Run(v *C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
val, err := c.f(v)
|
||||||
|
if err != nil {
|
||||||
|
return reflect.Value{}, err
|
||||||
|
}
|
||||||
|
if !val.Type().ConvertibleTo(c.typ) {
|
||||||
|
return reflect.Value{}, fmt.Errorf("cannot convert %s to %s", val.Type(), c.typ)
|
||||||
|
}
|
||||||
|
return val.Convert(c.typ), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackArgInt64(v *C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
|
||||||
|
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(int64(C.sqlite3_value_int64(v))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackArgBool(v *C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
|
||||||
|
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
|
||||||
|
}
|
||||||
|
i := int64(C.sqlite3_value_int64(v))
|
||||||
|
val := false
|
||||||
|
if i != 0 {
|
||||||
|
val = true
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(val), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackArgFloat64(v *C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
if C.sqlite3_value_type(v) != C.SQLITE_FLOAT {
|
||||||
|
return reflect.Value{}, fmt.Errorf("argument must be a FLOAT")
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(float64(C.sqlite3_value_double(v))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackArgBytes(v *C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
switch C.sqlite3_value_type(v) {
|
||||||
|
case C.SQLITE_BLOB:
|
||||||
|
l := C.sqlite3_value_bytes(v)
|
||||||
|
p := C.sqlite3_value_blob(v)
|
||||||
|
return reflect.ValueOf(C.GoBytes(p, l)), nil
|
||||||
|
case C.SQLITE_TEXT:
|
||||||
|
l := C.sqlite3_value_bytes(v)
|
||||||
|
c := unsafe.Pointer(C.sqlite3_value_text(v))
|
||||||
|
return reflect.ValueOf(C.GoBytes(c, l)), nil
|
||||||
|
default:
|
||||||
|
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackArgString(v *C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
switch C.sqlite3_value_type(v) {
|
||||||
|
case C.SQLITE_BLOB:
|
||||||
|
l := C.sqlite3_value_bytes(v)
|
||||||
|
p := (*C.char)(C.sqlite3_value_blob(v))
|
||||||
|
return reflect.ValueOf(C.GoStringN(p, l)), nil
|
||||||
|
case C.SQLITE_TEXT:
|
||||||
|
c := (*C.char)(unsafe.Pointer(C.sqlite3_value_text(v)))
|
||||||
|
return reflect.ValueOf(C.GoString(c)), nil
|
||||||
|
default:
|
||||||
|
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackArgGeneric(v *C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
switch C.sqlite3_value_type(v) {
|
||||||
|
case C.SQLITE_INTEGER:
|
||||||
|
return callbackArgInt64(v)
|
||||||
|
case C.SQLITE_FLOAT:
|
||||||
|
return callbackArgFloat64(v)
|
||||||
|
case C.SQLITE_TEXT:
|
||||||
|
return callbackArgString(v)
|
||||||
|
case C.SQLITE_BLOB:
|
||||||
|
return callbackArgBytes(v)
|
||||||
|
case C.SQLITE_NULL:
|
||||||
|
// Interpret NULL as a nil byte slice.
|
||||||
|
var ret []byte
|
||||||
|
return reflect.ValueOf(ret), nil
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackArg(typ reflect.Type) (callbackArgConverter, error) {
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Interface:
|
||||||
|
if typ.NumMethod() != 0 {
|
||||||
|
return nil, errors.New("the only supported interface type is interface{}")
|
||||||
|
}
|
||||||
|
return callbackArgGeneric, nil
|
||||||
|
case reflect.Slice:
|
||||||
|
if typ.Elem().Kind() != reflect.Uint8 {
|
||||||
|
return nil, errors.New("the only supported slice type is []byte")
|
||||||
|
}
|
||||||
|
return callbackArgBytes, nil
|
||||||
|
case reflect.String:
|
||||||
|
return callbackArgString, nil
|
||||||
|
case reflect.Bool:
|
||||||
|
return callbackArgBool, nil
|
||||||
|
case reflect.Int64:
|
||||||
|
return callbackArgInt64, nil
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||||
|
c := callbackArgCast{callbackArgInt64, typ}
|
||||||
|
return c.Run, nil
|
||||||
|
case reflect.Float64:
|
||||||
|
return callbackArgFloat64, nil
|
||||||
|
case reflect.Float32:
|
||||||
|
c := callbackArgCast{callbackArgFloat64, typ}
|
||||||
|
return c.Run, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("don't know how to convert to %s", typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackConvertArgs(argv []*C.sqlite3_value, converters []callbackArgConverter, variadic callbackArgConverter) ([]reflect.Value, error) {
|
||||||
|
var args []reflect.Value
|
||||||
|
|
||||||
|
if len(argv) < len(converters) {
|
||||||
|
return nil, fmt.Errorf("function requires at least %d arguments", len(converters))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, arg := range argv[:len(converters)] {
|
||||||
|
v, err := converters[i](arg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args = append(args, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if variadic != nil {
|
||||||
|
for _, arg := range argv[len(converters):] {
|
||||||
|
v, err := variadic(arg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args = append(args, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type callbackRetConverter func(*C.sqlite3_context, reflect.Value) error
|
||||||
|
|
||||||
|
func callbackRetInteger(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||||
|
switch v.Type().Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||||
|
v = v.Convert(reflect.TypeOf(int64(0)))
|
||||||
|
case reflect.Bool:
|
||||||
|
b := v.Interface().(bool)
|
||||||
|
if b {
|
||||||
|
v = reflect.ValueOf(int64(1))
|
||||||
|
} else {
|
||||||
|
v = reflect.ValueOf(int64(0))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cannot convert %s to INTEGER", v.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
C.sqlite3_result_int64(ctx, C.sqlite3_int64(v.Interface().(int64)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackRetFloat(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||||
|
switch v.Type().Kind() {
|
||||||
|
case reflect.Float64:
|
||||||
|
case reflect.Float32:
|
||||||
|
v = v.Convert(reflect.TypeOf(float64(0)))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cannot convert %s to FLOAT", v.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
C.sqlite3_result_double(ctx, C.double(v.Interface().(float64)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackRetBlob(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||||
|
if v.Type().Kind() != reflect.Slice || v.Type().Elem().Kind() != reflect.Uint8 {
|
||||||
|
return fmt.Errorf("cannot convert %s to BLOB", v.Type())
|
||||||
|
}
|
||||||
|
i := v.Interface()
|
||||||
|
if i == nil || len(i.([]byte)) == 0 {
|
||||||
|
C.sqlite3_result_null(ctx)
|
||||||
|
} else {
|
||||||
|
bs := i.([]byte)
|
||||||
|
C._sqlite3_result_blob(ctx, unsafe.Pointer(&bs[0]), C.int(len(bs)))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||||
|
if v.Type().Kind() != reflect.String {
|
||||||
|
return fmt.Errorf("cannot convert %s to TEXT", v.Type())
|
||||||
|
}
|
||||||
|
C._sqlite3_result_text(ctx, C.CString(v.Interface().(string)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackRetNil(ctx *C.sqlite3_context, v reflect.Value) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackRet(typ reflect.Type) (callbackRetConverter, error) {
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Interface:
|
||||||
|
errorInterface := reflect.TypeOf((*error)(nil)).Elem()
|
||||||
|
if typ.Implements(errorInterface) {
|
||||||
|
return callbackRetNil, nil
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case reflect.Slice:
|
||||||
|
if typ.Elem().Kind() != reflect.Uint8 {
|
||||||
|
return nil, errors.New("the only supported slice type is []byte")
|
||||||
|
}
|
||||||
|
return callbackRetBlob, nil
|
||||||
|
case reflect.String:
|
||||||
|
return callbackRetText, nil
|
||||||
|
case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
|
||||||
|
return callbackRetInteger, nil
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return callbackRetFloat, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("don't know how to convert to %s", typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func callbackError(ctx *C.sqlite3_context, err error) {
|
||||||
|
cstr := C.CString(err.Error())
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.sqlite3_result_error(ctx, cstr, C.int(-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test support code. Tests are not allowed to import "C", so we can't
|
||||||
|
// declare any functions that use C.sqlite3_value.
|
||||||
|
func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter {
|
||||||
|
return func(*C.sqlite3_value) (reflect.Value, error) {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
}
|
299
vendor/github.com/mattn/go-sqlite3/convert.go
generated
vendored
Normal file
299
vendor/github.com/mattn/go-sqlite3/convert.go
generated
vendored
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
// Extracted from Go database/sql source code
|
||||||
|
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Type conversions for Scan.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
||||||
|
|
||||||
|
// convertAssign copies to dest the value in src, converting it if possible.
|
||||||
|
// An error is returned if the copy would result in loss of information.
|
||||||
|
// dest should be a pointer type.
|
||||||
|
func convertAssign(dest, src interface{}) error {
|
||||||
|
// Common cases, without reflect.
|
||||||
|
switch s := src.(type) {
|
||||||
|
case string:
|
||||||
|
switch d := dest.(type) {
|
||||||
|
case *string:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = s
|
||||||
|
return nil
|
||||||
|
case *[]byte:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = []byte(s)
|
||||||
|
return nil
|
||||||
|
case *sql.RawBytes:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = append((*d)[:0], s...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case []byte:
|
||||||
|
switch d := dest.(type) {
|
||||||
|
case *string:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = string(s)
|
||||||
|
return nil
|
||||||
|
case *interface{}:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = cloneBytes(s)
|
||||||
|
return nil
|
||||||
|
case *[]byte:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = cloneBytes(s)
|
||||||
|
return nil
|
||||||
|
case *sql.RawBytes:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case time.Time:
|
||||||
|
switch d := dest.(type) {
|
||||||
|
case *time.Time:
|
||||||
|
*d = s
|
||||||
|
return nil
|
||||||
|
case *string:
|
||||||
|
*d = s.Format(time.RFC3339Nano)
|
||||||
|
return nil
|
||||||
|
case *[]byte:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = []byte(s.Format(time.RFC3339Nano))
|
||||||
|
return nil
|
||||||
|
case *sql.RawBytes:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
switch d := dest.(type) {
|
||||||
|
case *interface{}:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = nil
|
||||||
|
return nil
|
||||||
|
case *[]byte:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = nil
|
||||||
|
return nil
|
||||||
|
case *sql.RawBytes:
|
||||||
|
if d == nil {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
*d = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sv reflect.Value
|
||||||
|
|
||||||
|
switch d := dest.(type) {
|
||||||
|
case *string:
|
||||||
|
sv = reflect.ValueOf(src)
|
||||||
|
switch sv.Kind() {
|
||||||
|
case reflect.Bool,
|
||||||
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
|
reflect.Float32, reflect.Float64:
|
||||||
|
*d = asString(src)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case *[]byte:
|
||||||
|
sv = reflect.ValueOf(src)
|
||||||
|
if b, ok := asBytes(nil, sv); ok {
|
||||||
|
*d = b
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case *sql.RawBytes:
|
||||||
|
sv = reflect.ValueOf(src)
|
||||||
|
if b, ok := asBytes([]byte(*d)[:0], sv); ok {
|
||||||
|
*d = sql.RawBytes(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case *bool:
|
||||||
|
bv, err := driver.Bool.ConvertValue(src)
|
||||||
|
if err == nil {
|
||||||
|
*d = bv.(bool)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
case *interface{}:
|
||||||
|
*d = src
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if scanner, ok := dest.(sql.Scanner); ok {
|
||||||
|
return scanner.Scan(src)
|
||||||
|
}
|
||||||
|
|
||||||
|
dpv := reflect.ValueOf(dest)
|
||||||
|
if dpv.Kind() != reflect.Ptr {
|
||||||
|
return errors.New("destination not a pointer")
|
||||||
|
}
|
||||||
|
if dpv.IsNil() {
|
||||||
|
return errNilPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sv.IsValid() {
|
||||||
|
sv = reflect.ValueOf(src)
|
||||||
|
}
|
||||||
|
|
||||||
|
dv := reflect.Indirect(dpv)
|
||||||
|
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
|
||||||
|
switch b := src.(type) {
|
||||||
|
case []byte:
|
||||||
|
dv.Set(reflect.ValueOf(cloneBytes(b)))
|
||||||
|
default:
|
||||||
|
dv.Set(sv)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
|
||||||
|
dv.Set(sv.Convert(dv.Type()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following conversions use a string value as an intermediate representation
|
||||||
|
// to convert between various numeric types.
|
||||||
|
//
|
||||||
|
// This also allows scanning into user defined types such as "type Int int64".
|
||||||
|
// For symmetry, also check for string destination types.
|
||||||
|
switch dv.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
if src == nil {
|
||||||
|
dv.Set(reflect.Zero(dv.Type()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dv.Set(reflect.New(dv.Type().Elem()))
|
||||||
|
return convertAssign(dv.Interface(), src)
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
s := asString(src)
|
||||||
|
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
|
||||||
|
if err != nil {
|
||||||
|
err = strconvErr(err)
|
||||||
|
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||||
|
}
|
||||||
|
dv.SetInt(i64)
|
||||||
|
return nil
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
s := asString(src)
|
||||||
|
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
|
||||||
|
if err != nil {
|
||||||
|
err = strconvErr(err)
|
||||||
|
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||||
|
}
|
||||||
|
dv.SetUint(u64)
|
||||||
|
return nil
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
s := asString(src)
|
||||||
|
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
|
||||||
|
if err != nil {
|
||||||
|
err = strconvErr(err)
|
||||||
|
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||||
|
}
|
||||||
|
dv.SetFloat(f64)
|
||||||
|
return nil
|
||||||
|
case reflect.String:
|
||||||
|
switch v := src.(type) {
|
||||||
|
case string:
|
||||||
|
dv.SetString(v)
|
||||||
|
return nil
|
||||||
|
case []byte:
|
||||||
|
dv.SetString(string(v))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func strconvErr(err error) error {
|
||||||
|
if ne, ok := err.(*strconv.NumError); ok {
|
||||||
|
return ne.Err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneBytes(b []byte) []byte {
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c := make([]byte, len(b))
|
||||||
|
copy(c, b)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func asString(src interface{}) string {
|
||||||
|
switch v := src.(type) {
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case []byte:
|
||||||
|
return string(v)
|
||||||
|
}
|
||||||
|
rv := reflect.ValueOf(src)
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return strconv.FormatInt(rv.Int(), 10)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return strconv.FormatUint(rv.Uint(), 10)
|
||||||
|
case reflect.Float64:
|
||||||
|
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
|
||||||
|
case reflect.Float32:
|
||||||
|
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
|
||||||
|
case reflect.Bool:
|
||||||
|
return strconv.FormatBool(rv.Bool())
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return strconv.AppendInt(buf, rv.Int(), 10), true
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return strconv.AppendUint(buf, rv.Uint(), 10), true
|
||||||
|
case reflect.Float32:
|
||||||
|
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
|
||||||
|
case reflect.Float64:
|
||||||
|
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
|
||||||
|
case reflect.Bool:
|
||||||
|
return strconv.AppendBool(buf, rv.Bool()), true
|
||||||
|
case reflect.String:
|
||||||
|
s := rv.String()
|
||||||
|
return append(buf, s...), true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
135
vendor/github.com/mattn/go-sqlite3/doc.go
generated
vendored
Normal file
135
vendor/github.com/mattn/go-sqlite3/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
Package sqlite3 provides interface to SQLite3 databases.
|
||||||
|
|
||||||
|
This works as a driver for database/sql.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
|
||||||
|
go get github.com/mattn/go-sqlite3
|
||||||
|
|
||||||
|
Supported Types
|
||||||
|
|
||||||
|
Currently, go-sqlite3 supports the following data types.
|
||||||
|
|
||||||
|
+------------------------------+
|
||||||
|
|go | sqlite3 |
|
||||||
|
|----------|-------------------|
|
||||||
|
|nil | null |
|
||||||
|
|int | integer |
|
||||||
|
|int64 | integer |
|
||||||
|
|float64 | float |
|
||||||
|
|bool | integer |
|
||||||
|
|[]byte | blob |
|
||||||
|
|string | text |
|
||||||
|
|time.Time | timestamp/datetime|
|
||||||
|
+------------------------------+
|
||||||
|
|
||||||
|
SQLite3 Extension
|
||||||
|
|
||||||
|
You can write your own extension module for sqlite3. For example, below is an
|
||||||
|
extension for a Regexp matcher operation.
|
||||||
|
|
||||||
|
#include <pcre.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sqlite3ext.h>
|
||||||
|
|
||||||
|
SQLITE_EXTENSION_INIT1
|
||||||
|
static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
||||||
|
if (argc >= 2) {
|
||||||
|
const char *target = (const char *)sqlite3_value_text(argv[1]);
|
||||||
|
const char *pattern = (const char *)sqlite3_value_text(argv[0]);
|
||||||
|
const char* errstr = NULL;
|
||||||
|
int erroff = 0;
|
||||||
|
int vec[500];
|
||||||
|
int n, rc;
|
||||||
|
pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
|
||||||
|
rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
|
||||||
|
if (rc <= 0) {
|
||||||
|
sqlite3_result_error(context, errstr, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sqlite3_result_int(context, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
int sqlite3_extension_init(sqlite3 *db, char **errmsg,
|
||||||
|
const sqlite3_api_routines *api) {
|
||||||
|
SQLITE_EXTENSION_INIT2(api);
|
||||||
|
return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8,
|
||||||
|
(void*)db, regexp_func, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
It needs to be built as a so/dll shared library. And you need to register
|
||||||
|
the extension module like below.
|
||||||
|
|
||||||
|
sql.Register("sqlite3_with_extensions",
|
||||||
|
&sqlite3.SQLiteDriver{
|
||||||
|
Extensions: []string{
|
||||||
|
"sqlite3_mod_regexp",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Then, you can use this extension.
|
||||||
|
|
||||||
|
rows, err := db.Query("select text from mytable where name regexp '^golang'")
|
||||||
|
|
||||||
|
Connection Hook
|
||||||
|
|
||||||
|
You can hook and inject your code when the connection is established by setting
|
||||||
|
ConnectHook to get the SQLiteConn.
|
||||||
|
|
||||||
|
sql.Register("sqlite3_with_hook_example",
|
||||||
|
&sqlite3.SQLiteDriver{
|
||||||
|
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
|
||||||
|
sqlite3conn = append(sqlite3conn, conn)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
You can also use database/sql.Conn.Raw (Go >= 1.13):
|
||||||
|
|
||||||
|
conn, err := db.Conn(context.Background())
|
||||||
|
// if err != nil { ... }
|
||||||
|
defer conn.Close()
|
||||||
|
err = conn.Raw(func (driverConn interface{}) error {
|
||||||
|
sqliteConn := driverConn.(*sqlite3.SQLiteConn)
|
||||||
|
// ... use sqliteConn
|
||||||
|
})
|
||||||
|
// if err != nil { ... }
|
||||||
|
|
||||||
|
Go SQlite3 Extensions
|
||||||
|
|
||||||
|
If you want to register Go functions as SQLite extension functions
|
||||||
|
you can make a custom driver by calling RegisterFunction from
|
||||||
|
ConnectHook.
|
||||||
|
|
||||||
|
regex = func(re, s string) (bool, error) {
|
||||||
|
return regexp.MatchString(re, s)
|
||||||
|
}
|
||||||
|
sql.Register("sqlite3_extended",
|
||||||
|
&sqlite3.SQLiteDriver{
|
||||||
|
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
|
||||||
|
return conn.RegisterFunc("regexp", regex, true)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
You can then use the custom driver by passing its name to sql.Open.
|
||||||
|
|
||||||
|
var i int
|
||||||
|
conn, err := sql.Open("sqlite3_extended", "./foo.db")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = db.QueryRow(`SELECT regexp("foo.*", "seafood")`).Scan(&i)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
See the documentation of RegisterFunc for more details.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package sqlite3
|
150
vendor/github.com/mattn/go-sqlite3/error.go
generated
vendored
Normal file
150
vendor/github.com/mattn/go-sqlite3/error.go
generated
vendored
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
// ErrNo inherit errno.
|
||||||
|
type ErrNo int
|
||||||
|
|
||||||
|
// ErrNoMask is mask code.
|
||||||
|
const ErrNoMask C.int = 0xff
|
||||||
|
|
||||||
|
// ErrNoExtended is extended errno.
|
||||||
|
type ErrNoExtended int
|
||||||
|
|
||||||
|
// Error implement sqlite error code.
|
||||||
|
type Error struct {
|
||||||
|
Code ErrNo /* The error code returned by SQLite */
|
||||||
|
ExtendedCode ErrNoExtended /* The extended error code returned by SQLite */
|
||||||
|
SystemErrno syscall.Errno /* The system errno returned by the OS through SQLite, if applicable */
|
||||||
|
err string /* The error string returned by sqlite3_errmsg(),
|
||||||
|
this usually contains more specific details. */
|
||||||
|
}
|
||||||
|
|
||||||
|
// result codes from http://www.sqlite.org/c3ref/c_abort.html
|
||||||
|
var (
|
||||||
|
ErrError = ErrNo(1) /* SQL error or missing database */
|
||||||
|
ErrInternal = ErrNo(2) /* Internal logic error in SQLite */
|
||||||
|
ErrPerm = ErrNo(3) /* Access permission denied */
|
||||||
|
ErrAbort = ErrNo(4) /* Callback routine requested an abort */
|
||||||
|
ErrBusy = ErrNo(5) /* The database file is locked */
|
||||||
|
ErrLocked = ErrNo(6) /* A table in the database is locked */
|
||||||
|
ErrNomem = ErrNo(7) /* A malloc() failed */
|
||||||
|
ErrReadonly = ErrNo(8) /* Attempt to write a readonly database */
|
||||||
|
ErrInterrupt = ErrNo(9) /* Operation terminated by sqlite3_interrupt() */
|
||||||
|
ErrIoErr = ErrNo(10) /* Some kind of disk I/O error occurred */
|
||||||
|
ErrCorrupt = ErrNo(11) /* The database disk image is malformed */
|
||||||
|
ErrNotFound = ErrNo(12) /* Unknown opcode in sqlite3_file_control() */
|
||||||
|
ErrFull = ErrNo(13) /* Insertion failed because database is full */
|
||||||
|
ErrCantOpen = ErrNo(14) /* Unable to open the database file */
|
||||||
|
ErrProtocol = ErrNo(15) /* Database lock protocol error */
|
||||||
|
ErrEmpty = ErrNo(16) /* Database is empty */
|
||||||
|
ErrSchema = ErrNo(17) /* The database schema changed */
|
||||||
|
ErrTooBig = ErrNo(18) /* String or BLOB exceeds size limit */
|
||||||
|
ErrConstraint = ErrNo(19) /* Abort due to constraint violation */
|
||||||
|
ErrMismatch = ErrNo(20) /* Data type mismatch */
|
||||||
|
ErrMisuse = ErrNo(21) /* Library used incorrectly */
|
||||||
|
ErrNoLFS = ErrNo(22) /* Uses OS features not supported on host */
|
||||||
|
ErrAuth = ErrNo(23) /* Authorization denied */
|
||||||
|
ErrFormat = ErrNo(24) /* Auxiliary database format error */
|
||||||
|
ErrRange = ErrNo(25) /* 2nd parameter to sqlite3_bind out of range */
|
||||||
|
ErrNotADB = ErrNo(26) /* File opened that is not a database file */
|
||||||
|
ErrNotice = ErrNo(27) /* Notifications from sqlite3_log() */
|
||||||
|
ErrWarning = ErrNo(28) /* Warnings from sqlite3_log() */
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error return error message from errno.
|
||||||
|
func (err ErrNo) Error() string {
|
||||||
|
return Error{Code: err}.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend return extended errno.
|
||||||
|
func (err ErrNo) Extend(by int) ErrNoExtended {
|
||||||
|
return ErrNoExtended(int(err) | (by << 8))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error return error message that is extended code.
|
||||||
|
func (err ErrNoExtended) Error() string {
|
||||||
|
return Error{Code: ErrNo(C.int(err) & ErrNoMask), ExtendedCode: err}.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err Error) Error() string {
|
||||||
|
var str string
|
||||||
|
if err.err != "" {
|
||||||
|
str = err.err
|
||||||
|
} else {
|
||||||
|
str = C.GoString(C.sqlite3_errstr(C.int(err.Code)))
|
||||||
|
}
|
||||||
|
if err.SystemErrno != 0 {
|
||||||
|
str += ": " + err.SystemErrno.Error()
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// result codes from http://www.sqlite.org/c3ref/c_abort_rollback.html
|
||||||
|
var (
|
||||||
|
ErrIoErrRead = ErrIoErr.Extend(1)
|
||||||
|
ErrIoErrShortRead = ErrIoErr.Extend(2)
|
||||||
|
ErrIoErrWrite = ErrIoErr.Extend(3)
|
||||||
|
ErrIoErrFsync = ErrIoErr.Extend(4)
|
||||||
|
ErrIoErrDirFsync = ErrIoErr.Extend(5)
|
||||||
|
ErrIoErrTruncate = ErrIoErr.Extend(6)
|
||||||
|
ErrIoErrFstat = ErrIoErr.Extend(7)
|
||||||
|
ErrIoErrUnlock = ErrIoErr.Extend(8)
|
||||||
|
ErrIoErrRDlock = ErrIoErr.Extend(9)
|
||||||
|
ErrIoErrDelete = ErrIoErr.Extend(10)
|
||||||
|
ErrIoErrBlocked = ErrIoErr.Extend(11)
|
||||||
|
ErrIoErrNoMem = ErrIoErr.Extend(12)
|
||||||
|
ErrIoErrAccess = ErrIoErr.Extend(13)
|
||||||
|
ErrIoErrCheckReservedLock = ErrIoErr.Extend(14)
|
||||||
|
ErrIoErrLock = ErrIoErr.Extend(15)
|
||||||
|
ErrIoErrClose = ErrIoErr.Extend(16)
|
||||||
|
ErrIoErrDirClose = ErrIoErr.Extend(17)
|
||||||
|
ErrIoErrSHMOpen = ErrIoErr.Extend(18)
|
||||||
|
ErrIoErrSHMSize = ErrIoErr.Extend(19)
|
||||||
|
ErrIoErrSHMLock = ErrIoErr.Extend(20)
|
||||||
|
ErrIoErrSHMMap = ErrIoErr.Extend(21)
|
||||||
|
ErrIoErrSeek = ErrIoErr.Extend(22)
|
||||||
|
ErrIoErrDeleteNoent = ErrIoErr.Extend(23)
|
||||||
|
ErrIoErrMMap = ErrIoErr.Extend(24)
|
||||||
|
ErrIoErrGetTempPath = ErrIoErr.Extend(25)
|
||||||
|
ErrIoErrConvPath = ErrIoErr.Extend(26)
|
||||||
|
ErrLockedSharedCache = ErrLocked.Extend(1)
|
||||||
|
ErrBusyRecovery = ErrBusy.Extend(1)
|
||||||
|
ErrBusySnapshot = ErrBusy.Extend(2)
|
||||||
|
ErrCantOpenNoTempDir = ErrCantOpen.Extend(1)
|
||||||
|
ErrCantOpenIsDir = ErrCantOpen.Extend(2)
|
||||||
|
ErrCantOpenFullPath = ErrCantOpen.Extend(3)
|
||||||
|
ErrCantOpenConvPath = ErrCantOpen.Extend(4)
|
||||||
|
ErrCorruptVTab = ErrCorrupt.Extend(1)
|
||||||
|
ErrReadonlyRecovery = ErrReadonly.Extend(1)
|
||||||
|
ErrReadonlyCantLock = ErrReadonly.Extend(2)
|
||||||
|
ErrReadonlyRollback = ErrReadonly.Extend(3)
|
||||||
|
ErrReadonlyDbMoved = ErrReadonly.Extend(4)
|
||||||
|
ErrAbortRollback = ErrAbort.Extend(2)
|
||||||
|
ErrConstraintCheck = ErrConstraint.Extend(1)
|
||||||
|
ErrConstraintCommitHook = ErrConstraint.Extend(2)
|
||||||
|
ErrConstraintForeignKey = ErrConstraint.Extend(3)
|
||||||
|
ErrConstraintFunction = ErrConstraint.Extend(4)
|
||||||
|
ErrConstraintNotNull = ErrConstraint.Extend(5)
|
||||||
|
ErrConstraintPrimaryKey = ErrConstraint.Extend(6)
|
||||||
|
ErrConstraintTrigger = ErrConstraint.Extend(7)
|
||||||
|
ErrConstraintUnique = ErrConstraint.Extend(8)
|
||||||
|
ErrConstraintVTab = ErrConstraint.Extend(9)
|
||||||
|
ErrConstraintRowID = ErrConstraint.Extend(10)
|
||||||
|
ErrNoticeRecoverWAL = ErrNotice.Extend(1)
|
||||||
|
ErrNoticeRecoverRollback = ErrNotice.Extend(2)
|
||||||
|
ErrWarningAutoIndex = ErrWarning.Extend(1)
|
||||||
|
)
|
235877
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
Normal file
235877
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
12454
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
Normal file
12454
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
2183
vendor/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
Normal file
2183
vendor/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
103
vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
generated
vendored
Normal file
103
vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
// These wrappers are necessary because SQLITE_TRANSIENT
|
||||||
|
// is a pointer constant, and cgo doesn't translate them correctly.
|
||||||
|
|
||||||
|
static inline void my_result_text(sqlite3_context *ctx, char *p, int np) {
|
||||||
|
sqlite3_result_text(ctx, p, np, SQLITE_TRANSIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void my_result_blob(sqlite3_context *ctx, void *p, int np) {
|
||||||
|
sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const i64 = unsafe.Sizeof(int(0)) > 4
|
||||||
|
|
||||||
|
// SQLiteContext behave sqlite3_context
|
||||||
|
type SQLiteContext C.sqlite3_context
|
||||||
|
|
||||||
|
// ResultBool sets the result of an SQL function.
|
||||||
|
func (c *SQLiteContext) ResultBool(b bool) {
|
||||||
|
if b {
|
||||||
|
c.ResultInt(1)
|
||||||
|
} else {
|
||||||
|
c.ResultInt(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultBlob sets the result of an SQL function.
|
||||||
|
// See: sqlite3_result_blob, http://sqlite.org/c3ref/result_blob.html
|
||||||
|
func (c *SQLiteContext) ResultBlob(b []byte) {
|
||||||
|
if i64 && len(b) > math.MaxInt32 {
|
||||||
|
C.sqlite3_result_error_toobig((*C.sqlite3_context)(c))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var p *byte
|
||||||
|
if len(b) > 0 {
|
||||||
|
p = &b[0]
|
||||||
|
}
|
||||||
|
C.my_result_blob((*C.sqlite3_context)(c), unsafe.Pointer(p), C.int(len(b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultDouble sets the result of an SQL function.
|
||||||
|
// See: sqlite3_result_double, http://sqlite.org/c3ref/result_blob.html
|
||||||
|
func (c *SQLiteContext) ResultDouble(d float64) {
|
||||||
|
C.sqlite3_result_double((*C.sqlite3_context)(c), C.double(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultInt sets the result of an SQL function.
|
||||||
|
// See: sqlite3_result_int, http://sqlite.org/c3ref/result_blob.html
|
||||||
|
func (c *SQLiteContext) ResultInt(i int) {
|
||||||
|
if i64 && (i > math.MaxInt32 || i < math.MinInt32) {
|
||||||
|
C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i))
|
||||||
|
} else {
|
||||||
|
C.sqlite3_result_int((*C.sqlite3_context)(c), C.int(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultInt64 sets the result of an SQL function.
|
||||||
|
// See: sqlite3_result_int64, http://sqlite.org/c3ref/result_blob.html
|
||||||
|
func (c *SQLiteContext) ResultInt64(i int64) {
|
||||||
|
C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultNull sets the result of an SQL function.
|
||||||
|
// See: sqlite3_result_null, http://sqlite.org/c3ref/result_blob.html
|
||||||
|
func (c *SQLiteContext) ResultNull() {
|
||||||
|
C.sqlite3_result_null((*C.sqlite3_context)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultText sets the result of an SQL function.
|
||||||
|
// See: sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html
|
||||||
|
func (c *SQLiteContext) ResultText(s string) {
|
||||||
|
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||||
|
cs, l := (*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len)
|
||||||
|
C.my_result_text((*C.sqlite3_context)(c), cs, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultZeroblob sets the result of an SQL function.
|
||||||
|
// See: sqlite3_result_zeroblob, http://sqlite.org/c3ref/result_blob.html
|
||||||
|
func (c *SQLiteContext) ResultZeroblob(n int) {
|
||||||
|
C.sqlite3_result_zeroblob((*C.sqlite3_context)(c), C.int(n))
|
||||||
|
}
|
120
vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go
generated
vendored
Normal file
120
vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file provides several different implementations for the
|
||||||
|
// default embedded sqlite_crypt function.
|
||||||
|
// This function is uses a caesar-cypher by default
|
||||||
|
// and is used within the UserAuthentication module to encode
|
||||||
|
// the password.
|
||||||
|
//
|
||||||
|
// The provided functions can be used as an overload to the sqlite_crypt
|
||||||
|
// function through the use of the RegisterFunc on the connection.
|
||||||
|
//
|
||||||
|
// Because the functions can serv a purpose to an end-user
|
||||||
|
// without using the UserAuthentication module
|
||||||
|
// the functions are default compiled in.
|
||||||
|
//
|
||||||
|
// From SQLITE3 - user-auth.txt
|
||||||
|
// The sqlite_user.pw field is encoded by a built-in SQL function
|
||||||
|
// "sqlite_crypt(X,Y)". The two arguments are both BLOBs. The first argument
|
||||||
|
// is the plaintext password supplied to the sqlite3_user_authenticate()
|
||||||
|
// interface. The second argument is the sqlite_user.pw value and is supplied
|
||||||
|
// so that the function can extract the "salt" used by the password encoder.
|
||||||
|
// The result of sqlite_crypt(X,Y) is another blob which is the value that
|
||||||
|
// ends up being stored in sqlite_user.pw. To verify credentials X supplied
|
||||||
|
// by the sqlite3_user_authenticate() routine, SQLite runs:
|
||||||
|
//
|
||||||
|
// sqlite_user.pw == sqlite_crypt(X, sqlite_user.pw)
|
||||||
|
//
|
||||||
|
// To compute an appropriate sqlite_user.pw value from a new or modified
|
||||||
|
// password X, sqlite_crypt(X,NULL) is run. A new random salt is selected
|
||||||
|
// when the second argument is NULL.
|
||||||
|
//
|
||||||
|
// The built-in version of of sqlite_crypt() uses a simple Caesar-cypher
|
||||||
|
// which prevents passwords from being revealed by searching the raw database
|
||||||
|
// for ASCII text, but is otherwise trivally broken. For better password
|
||||||
|
// security, the database should be encrypted using the SQLite Encryption
|
||||||
|
// Extension or similar technology. Or, the application can use the
|
||||||
|
// sqlite3_create_function() interface to provide an alternative
|
||||||
|
// implementation of sqlite_crypt() that computes a stronger password hash,
|
||||||
|
// perhaps using a cryptographic hash function like SHA1.
|
||||||
|
|
||||||
|
// CryptEncoderSHA1 encodes a password with SHA1
|
||||||
|
func CryptEncoderSHA1(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha1.Sum(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA1 encodes a password with SHA1 with the
|
||||||
|
// configured salt.
|
||||||
|
func CryptEncoderSSHA1(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha1.Sum(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSHA256 encodes a password with SHA256
|
||||||
|
func CryptEncoderSHA256(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha256.Sum256(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA256 encodes a password with SHA256
|
||||||
|
// with the configured salt
|
||||||
|
func CryptEncoderSSHA256(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha256.Sum256(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSHA384 encodes a password with SHA384
|
||||||
|
func CryptEncoderSHA384(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha512.Sum384(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA384 encodes a password with SHA384
|
||||||
|
// with the configured salt
|
||||||
|
func CryptEncoderSSHA384(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha512.Sum384(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSHA512 encodes a password with SHA512
|
||||||
|
func CryptEncoderSHA512(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha512.Sum512(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA512 encodes a password with SHA512
|
||||||
|
// with the configured salt
|
||||||
|
func CryptEncoderSSHA512(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha512.Sum512(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOF
|
70
vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go
generated
vendored
Normal file
70
vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ping implement Pinger.
|
||||||
|
func (c *SQLiteConn) Ping(ctx context.Context) error {
|
||||||
|
if c.db == nil {
|
||||||
|
// must be ErrBadConn for sql to close the database
|
||||||
|
return driver.ErrBadConn
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryContext implement QueryerContext.
|
||||||
|
func (c *SQLiteConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
|
||||||
|
list := make([]namedValue, len(args))
|
||||||
|
for i, nv := range args {
|
||||||
|
list[i] = namedValue(nv)
|
||||||
|
}
|
||||||
|
return c.query(ctx, query, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecContext implement ExecerContext.
|
||||||
|
func (c *SQLiteConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
|
||||||
|
list := make([]namedValue, len(args))
|
||||||
|
for i, nv := range args {
|
||||||
|
list[i] = namedValue(nv)
|
||||||
|
}
|
||||||
|
return c.exec(ctx, query, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareContext implement ConnPrepareContext.
|
||||||
|
func (c *SQLiteConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
|
||||||
|
return c.prepare(ctx, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeginTx implement ConnBeginTx.
|
||||||
|
func (c *SQLiteConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
||||||
|
return c.begin(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryContext implement QueryerContext.
|
||||||
|
func (s *SQLiteStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
|
||||||
|
list := make([]namedValue, len(args))
|
||||||
|
for i, nv := range args {
|
||||||
|
list[i] = namedValue(nv)
|
||||||
|
}
|
||||||
|
return s.query(ctx, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecContext implement ExecerContext.
|
||||||
|
func (s *SQLiteStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
|
||||||
|
list := make([]namedValue, len(args))
|
||||||
|
for i, nv := range args {
|
||||||
|
list[i] = namedValue(nv)
|
||||||
|
}
|
||||||
|
return s.exec(ctx, list)
|
||||||
|
}
|
19
vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
generated
vendored
Normal file
19
vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build libsqlite3
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DUSE_LIBSQLITE3
|
||||||
|
#cgo linux LDFLAGS: -lsqlite3
|
||||||
|
#cgo darwin LDFLAGS: -L/usr/local/opt/sqlite/lib -lsqlite3
|
||||||
|
#cgo darwin CFLAGS: -I/usr/local/opt/sqlite/include
|
||||||
|
#cgo openbsd LDFLAGS: -lsqlite3
|
||||||
|
#cgo solaris LDFLAGS: -lsqlite3
|
||||||
|
#cgo windows LDFLAGS: -lsqlite3
|
||||||
|
*/
|
||||||
|
import "C"
|
84
vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
generated
vendored
Normal file
84
vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !sqlite_omit_load_extension
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *SQLiteConn) loadExtensions(extensions []string) error {
|
||||||
|
rv := C.sqlite3_enable_load_extension(c.db, 1)
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, extension := range extensions {
|
||||||
|
if err := c.loadExtension(extension, nil); err != nil {
|
||||||
|
C.sqlite3_enable_load_extension(c.db, 0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = C.sqlite3_enable_load_extension(c.db, 0)
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadExtension load the sqlite3 extension.
|
||||||
|
func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
|
||||||
|
rv := C.sqlite3_enable_load_extension(c.db, 1)
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.loadExtension(lib, &entry); err != nil {
|
||||||
|
C.sqlite3_enable_load_extension(c.db, 0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = C.sqlite3_enable_load_extension(c.db, 0)
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return errors.New(C.GoString(C.sqlite3_errmsg(c.db)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SQLiteConn) loadExtension(lib string, entry *string) error {
|
||||||
|
clib := C.CString(lib)
|
||||||
|
defer C.free(unsafe.Pointer(clib))
|
||||||
|
|
||||||
|
var centry *C.char
|
||||||
|
if entry != nil {
|
||||||
|
centry = C.CString(*entry)
|
||||||
|
defer C.free(unsafe.Pointer(centry))
|
||||||
|
}
|
||||||
|
|
||||||
|
var errMsg *C.char
|
||||||
|
defer C.sqlite3_free(unsafe.Pointer(errMsg))
|
||||||
|
|
||||||
|
rv := C.sqlite3_load_extension(c.db, clib, centry, &errMsg)
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return errors.New(C.GoString(errMsg))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
24
vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension_omit.go
generated
vendored
Normal file
24
vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension_omit.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_omit_load_extension
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_OMIT_LOAD_EXTENSION
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *SQLiteConn) loadExtensions(extensions []string) error {
|
||||||
|
return errors.New("Extensions have been disabled for static builds")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SQLiteConn) LoadExtension(lib string, entry string) error {
|
||||||
|
return errors.New("Extensions have been disabled for static builds")
|
||||||
|
}
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_allow_uri_authority.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_allow_uri_authority.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_allow_uri_authority
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_ALLOW_URI_AUTHORITY
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
16
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_app_armor.go
generated
vendored
Normal file
16
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_app_armor.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !windows
|
||||||
|
// +build sqlite_app_armor
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_API_ARMOR
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
21
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_column_metadata.go
generated
vendored
Normal file
21
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_column_metadata.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// +build sqlite_column_metadata
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_COLUMN_METADATA
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// ColumnTableName returns the table that is the origin of a particular result
|
||||||
|
// column in a SELECT statement.
|
||||||
|
//
|
||||||
|
// See https://www.sqlite.org/c3ref/column_database_name.html
|
||||||
|
func (s *SQLiteStmt) ColumnTableName(n int) string {
|
||||||
|
return C.GoString(C.sqlite3_column_table_name(s.s, C.int(n)))
|
||||||
|
}
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_foreign_keys.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_foreign_keys.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_foreign_keys
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_DEFAULT_FOREIGN_KEYS=1
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
14
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_fts5.go
generated
vendored
Normal file
14
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_fts5.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_fts5 fts5
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_FTS5
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
17
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_icu.go
generated
vendored
Normal file
17
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_icu.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_icu icu
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -licuuc -licui18n
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_ICU
|
||||||
|
#cgo darwin CFLAGS: -I/usr/local/opt/icu4c/include
|
||||||
|
#cgo darwin LDFLAGS: -L/usr/local/opt/icu4c/lib
|
||||||
|
#cgo openbsd LDFLAGS: -lsqlite3
|
||||||
|
*/
|
||||||
|
import "C"
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_introspect.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_introspect.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_introspect
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_INTROSPECTION_PRAGMAS
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
13
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_json1.go
generated
vendored
Normal file
13
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_json1.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_json sqlite_json1 json1
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_JSON1
|
||||||
|
*/
|
||||||
|
import "C"
|
20
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate.go
generated
vendored
Normal file
20
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (C) 2019 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
// Copyright (C) 2018 segment.com <friends@segment.com>
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
// SQLitePreUpdateData represents all of the data available during a
|
||||||
|
// pre-update hook call.
|
||||||
|
type SQLitePreUpdateData struct {
|
||||||
|
Conn *SQLiteConn
|
||||||
|
Op int
|
||||||
|
DatabaseName string
|
||||||
|
TableName string
|
||||||
|
OldRowID int64
|
||||||
|
NewRowID int64
|
||||||
|
}
|
112
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_hook.go
generated
vendored
Normal file
112
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_hook.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
// Copyright (C) 2019 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
// Copyright (C) 2018 segment.com <friends@segment.com>
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_preupdate_hook
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_PREUPDATE_HOOK
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void preUpdateHookTrampoline(void*, sqlite3 *, int, char *, char *, sqlite3_int64, sqlite3_int64);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterPreUpdateHook sets the pre-update hook for a connection.
|
||||||
|
//
|
||||||
|
// The callback is passed a SQLitePreUpdateData struct with the data for
|
||||||
|
// the update, as well as methods for fetching copies of impacted data.
|
||||||
|
//
|
||||||
|
// If there is an existing update hook for this connection, it will be
|
||||||
|
// removed. If callback is nil the existing hook (if any) will be removed
|
||||||
|
// without creating a new one.
|
||||||
|
func (c *SQLiteConn) RegisterPreUpdateHook(callback func(SQLitePreUpdateData)) {
|
||||||
|
if callback == nil {
|
||||||
|
C.sqlite3_preupdate_hook(c.db, nil, nil)
|
||||||
|
} else {
|
||||||
|
C.sqlite3_preupdate_hook(c.db, (*[0]byte)(unsafe.Pointer(C.preUpdateHookTrampoline)), unsafe.Pointer(newHandle(c, callback)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth returns the source path of the write, see sqlite3_preupdate_depth()
|
||||||
|
func (d *SQLitePreUpdateData) Depth() int {
|
||||||
|
return int(C.sqlite3_preupdate_depth(d.Conn.db))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the number of columns in the row
|
||||||
|
func (d *SQLitePreUpdateData) Count() int {
|
||||||
|
return int(C.sqlite3_preupdate_count(d.Conn.db))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLitePreUpdateData) row(dest []interface{}, new bool) error {
|
||||||
|
for i := 0; i < d.Count() && i < len(dest); i++ {
|
||||||
|
var val *C.sqlite3_value
|
||||||
|
var src interface{}
|
||||||
|
|
||||||
|
// Initially I tried making this just a function pointer argument, but
|
||||||
|
// it's absurdly complicated to pass C function pointers.
|
||||||
|
if new {
|
||||||
|
C.sqlite3_preupdate_new(d.Conn.db, C.int(i), &val)
|
||||||
|
} else {
|
||||||
|
C.sqlite3_preupdate_old(d.Conn.db, C.int(i), &val)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch C.sqlite3_value_type(val) {
|
||||||
|
case C.SQLITE_INTEGER:
|
||||||
|
src = int64(C.sqlite3_value_int64(val))
|
||||||
|
case C.SQLITE_FLOAT:
|
||||||
|
src = float64(C.sqlite3_value_double(val))
|
||||||
|
case C.SQLITE_BLOB:
|
||||||
|
len := C.sqlite3_value_bytes(val)
|
||||||
|
blobptr := C.sqlite3_value_blob(val)
|
||||||
|
src = C.GoBytes(blobptr, len)
|
||||||
|
case C.SQLITE_TEXT:
|
||||||
|
len := C.sqlite3_value_bytes(val)
|
||||||
|
cstrptr := unsafe.Pointer(C.sqlite3_value_text(val))
|
||||||
|
src = C.GoBytes(cstrptr, len)
|
||||||
|
case C.SQLITE_NULL:
|
||||||
|
src = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := convertAssign(&dest[i], src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old populates dest with the row data to be replaced. This works similar to
|
||||||
|
// database/sql's Rows.Scan()
|
||||||
|
func (d *SQLitePreUpdateData) Old(dest ...interface{}) error {
|
||||||
|
if d.Op == SQLITE_INSERT {
|
||||||
|
return errors.New("There is no old row for INSERT operations")
|
||||||
|
}
|
||||||
|
return d.row(dest, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New populates dest with the replacement row data. This works similar to
|
||||||
|
// database/sql's Rows.Scan()
|
||||||
|
func (d *SQLitePreUpdateData) New(dest ...interface{}) error {
|
||||||
|
if d.Op == SQLITE_DELETE {
|
||||||
|
return errors.New("There is no new row for DELETE operations")
|
||||||
|
}
|
||||||
|
return d.row(dest, true)
|
||||||
|
}
|
21
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_omit.go
generated
vendored
Normal file
21
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_omit.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright (C) 2019 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
// Copyright (C) 2018 segment.com <friends@segment.com>
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !sqlite_preupdate_hook,cgo
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
// RegisterPreUpdateHook sets the pre-update hook for a connection.
|
||||||
|
//
|
||||||
|
// The callback is passed a SQLitePreUpdateData struct with the data for
|
||||||
|
// the update, as well as methods for fetching copies of impacted data.
|
||||||
|
//
|
||||||
|
// If there is an existing update hook for this connection, it will be
|
||||||
|
// removed. If callback is nil the existing hook (if any) will be removed
|
||||||
|
// without creating a new one.
|
||||||
|
func (c *SQLiteConn) RegisterPreUpdateHook(callback func(SQLitePreUpdateData)) {
|
||||||
|
// NOOP
|
||||||
|
}
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_secure_delete.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_secure_delete.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_secure_delete
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_SECURE_DELETE=1
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_secure_delete_fast.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_secure_delete_fast.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_secure_delete_fast
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_SECURE_DELETE=FAST
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_stat4.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_stat4.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_stat4
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_STAT4
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
85
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.c
generated
vendored
Normal file
85
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.c
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
|
||||||
|
extern int unlock_notify_wait(sqlite3 *db);
|
||||||
|
|
||||||
|
int
|
||||||
|
_sqlite3_step_blocking(sqlite3_stmt *stmt)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
sqlite3* db;
|
||||||
|
|
||||||
|
db = sqlite3_db_handle(stmt);
|
||||||
|
for (;;) {
|
||||||
|
rv = sqlite3_step(stmt);
|
||||||
|
if (rv != SQLITE_LOCKED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rv = unlock_notify_wait(db);
|
||||||
|
if (rv != SQLITE_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_sqlite3_step_row_blocking(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
sqlite3* db;
|
||||||
|
|
||||||
|
db = sqlite3_db_handle(stmt);
|
||||||
|
for (;;) {
|
||||||
|
rv = sqlite3_step(stmt);
|
||||||
|
if (rv!=SQLITE_LOCKED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rv = unlock_notify_wait(db);
|
||||||
|
if (rv != SQLITE_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
*rowid = (long long) sqlite3_last_insert_rowid(db);
|
||||||
|
*changes = (long long) sqlite3_changes(db);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rv = sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
|
||||||
|
if (rv!=SQLITE_LOCKED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rv = unlock_notify_wait(db);
|
||||||
|
if (rv != SQLITE_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
#endif
|
93
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go
generated
vendored
Normal file
93
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo
|
||||||
|
// +build sqlite_unlock_notify
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
|
||||||
|
extern void unlock_notify_callback(void *arg, int argc);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type unlock_notify_table struct {
|
||||||
|
sync.Mutex
|
||||||
|
seqnum uint
|
||||||
|
table map[uint]chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unt unlock_notify_table = unlock_notify_table{table: make(map[uint]chan struct{})}
|
||||||
|
|
||||||
|
func (t *unlock_notify_table) add(c chan struct{}) uint {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
h := t.seqnum
|
||||||
|
t.table[h] = c
|
||||||
|
t.seqnum++
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *unlock_notify_table) remove(h uint) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
delete(t.table, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *unlock_notify_table) get(h uint) chan struct{} {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
c, ok := t.table[h]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("Non-existent key for unlcok-notify channel: %d", h))
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
//export unlock_notify_callback
|
||||||
|
func unlock_notify_callback(argv unsafe.Pointer, argc C.int) {
|
||||||
|
for i := 0; i < int(argc); i++ {
|
||||||
|
parg := ((*(*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.uint)(nil))]*[1]uint)(argv))[i])
|
||||||
|
arg := *parg
|
||||||
|
h := arg[0]
|
||||||
|
c := unt.get(h)
|
||||||
|
c <- struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export unlock_notify_wait
|
||||||
|
func unlock_notify_wait(db *C.sqlite3) C.int {
|
||||||
|
// It has to be a bufferred channel to not block in sqlite_unlock_notify
|
||||||
|
// as sqlite_unlock_notify could invoke the callback before it returns.
|
||||||
|
c := make(chan struct{}, 1)
|
||||||
|
defer close(c)
|
||||||
|
|
||||||
|
h := unt.add(c)
|
||||||
|
defer unt.remove(h)
|
||||||
|
|
||||||
|
pargv := C.malloc(C.sizeof_uint)
|
||||||
|
defer C.free(pargv)
|
||||||
|
|
||||||
|
argv := (*[1]uint)(pargv)
|
||||||
|
argv[0] = h
|
||||||
|
if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C.unlock_notify_callback), unsafe.Pointer(pargv)); rv != C.SQLITE_OK {
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
<-c
|
||||||
|
|
||||||
|
return C.SQLITE_OK
|
||||||
|
}
|
289
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_userauth.go
generated
vendored
Normal file
289
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_userauth.go
generated
vendored
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_userauth
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_USER_AUTHENTICATION
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sqlite3_user_authenticate(sqlite3* db, const char* zUsername, const char* aPW, int nPW)
|
||||||
|
{
|
||||||
|
return sqlite3_user_authenticate(db, zUsername, aPW, nPW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sqlite3_user_add(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
|
||||||
|
{
|
||||||
|
return sqlite3_user_add(db, zUsername, aPW, nPW, isAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sqlite3_user_change(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
|
||||||
|
{
|
||||||
|
return sqlite3_user_change(db, zUsername, aPW, nPW, isAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sqlite3_user_delete(sqlite3* db, const char* zUsername)
|
||||||
|
{
|
||||||
|
return sqlite3_user_delete(db, zUsername);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sqlite3_auth_enabled(sqlite3* db)
|
||||||
|
{
|
||||||
|
int exists = -1;
|
||||||
|
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
sqlite3_prepare_v2(db, "select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';", -1, &stmt, NULL);
|
||||||
|
|
||||||
|
while ( sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
exists = sqlite3_column_int(stmt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SQLITE_AUTH = C.SQLITE_AUTH
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized")
|
||||||
|
ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Authenticate will perform an authentication of the provided username
|
||||||
|
// and password against the database.
|
||||||
|
//
|
||||||
|
// If a database contains the SQLITE_USER table, then the
|
||||||
|
// call to Authenticate must be invoked with an
|
||||||
|
// appropriate username and password prior to enable read and write
|
||||||
|
//access to the database.
|
||||||
|
//
|
||||||
|
// Return SQLITE_OK on success or SQLITE_ERROR if the username/password
|
||||||
|
// combination is incorrect or unknown.
|
||||||
|
//
|
||||||
|
// If the SQLITE_USER table is not present in the database file, then
|
||||||
|
// this interface is a harmless no-op returnning SQLITE_OK.
|
||||||
|
func (c *SQLiteConn) Authenticate(username, password string) error {
|
||||||
|
rv := c.authenticate(username, password)
|
||||||
|
switch rv {
|
||||||
|
case C.SQLITE_ERROR, C.SQLITE_AUTH:
|
||||||
|
return ErrUnauthorized
|
||||||
|
case C.SQLITE_OK:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// authenticate provides the actual authentication to SQLite.
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authenticate(username, password string) int {
|
||||||
|
// Allocate C Variables
|
||||||
|
cuser := C.CString(username)
|
||||||
|
cpass := C.CString(password)
|
||||||
|
|
||||||
|
// Free C Variables
|
||||||
|
defer func() {
|
||||||
|
C.free(unsafe.Pointer(cuser))
|
||||||
|
C.free(unsafe.Pointer(cpass))
|
||||||
|
}()
|
||||||
|
|
||||||
|
return int(C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthUserAdd can be used (by an admin user only)
|
||||||
|
// to create a new user. When called on a no-authentication-required
|
||||||
|
// database, this routine converts the database into an authentication-
|
||||||
|
// required database, automatically makes the added user an
|
||||||
|
// administrator, and logs in the current connection as that user.
|
||||||
|
// The AuthUserAdd only works for the "main" database, not
|
||||||
|
// for any ATTACH-ed databases. Any call to AuthUserAdd by a
|
||||||
|
// non-admin user results in an error.
|
||||||
|
func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
|
||||||
|
isAdmin := 0
|
||||||
|
if admin {
|
||||||
|
isAdmin = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := c.authUserAdd(username, password, isAdmin)
|
||||||
|
switch rv {
|
||||||
|
case C.SQLITE_ERROR, C.SQLITE_AUTH:
|
||||||
|
return ErrAdminRequired
|
||||||
|
case C.SQLITE_OK:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// authUserAdd enables the User Authentication if not enabled.
|
||||||
|
// Otherwise it will add a user.
|
||||||
|
//
|
||||||
|
// When user authentication is already enabled then this function
|
||||||
|
// can only be called by an admin.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
|
||||||
|
// Allocate C Variables
|
||||||
|
cuser := C.CString(username)
|
||||||
|
cpass := C.CString(password)
|
||||||
|
|
||||||
|
// Free C Variables
|
||||||
|
defer func() {
|
||||||
|
C.free(unsafe.Pointer(cuser))
|
||||||
|
C.free(unsafe.Pointer(cpass))
|
||||||
|
}()
|
||||||
|
|
||||||
|
return int(C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthUserChange can be used to change a users
|
||||||
|
// login credentials or admin privilege. Any user can change their own
|
||||||
|
// login credentials. Only an admin user can change another users login
|
||||||
|
// credentials or admin privilege setting. No user may change their own
|
||||||
|
// admin privilege setting.
|
||||||
|
func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
|
||||||
|
isAdmin := 0
|
||||||
|
if admin {
|
||||||
|
isAdmin = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := c.authUserChange(username, password, isAdmin)
|
||||||
|
switch rv {
|
||||||
|
case C.SQLITE_ERROR, C.SQLITE_AUTH:
|
||||||
|
return ErrAdminRequired
|
||||||
|
case C.SQLITE_OK:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// authUserChange allows to modify a user.
|
||||||
|
// Users can change their own password.
|
||||||
|
//
|
||||||
|
// Only admins can change passwords for other users
|
||||||
|
// and modify the admin flag.
|
||||||
|
//
|
||||||
|
// The admin flag of the current logged in user cannot be changed.
|
||||||
|
// THis ensures that their is always an admin.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
|
||||||
|
// Allocate C Variables
|
||||||
|
cuser := C.CString(username)
|
||||||
|
cpass := C.CString(password)
|
||||||
|
|
||||||
|
// Free C Variables
|
||||||
|
defer func() {
|
||||||
|
C.free(unsafe.Pointer(cuser))
|
||||||
|
C.free(unsafe.Pointer(cpass))
|
||||||
|
}()
|
||||||
|
|
||||||
|
return int(C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthUserDelete can be used (by an admin user only)
|
||||||
|
// to delete a user. The currently logged-in user cannot be deleted,
|
||||||
|
// which guarantees that there is always an admin user and hence that
|
||||||
|
// the database cannot be converted into a no-authentication-required
|
||||||
|
// database.
|
||||||
|
func (c *SQLiteConn) AuthUserDelete(username string) error {
|
||||||
|
rv := c.authUserDelete(username)
|
||||||
|
switch rv {
|
||||||
|
case C.SQLITE_ERROR, C.SQLITE_AUTH:
|
||||||
|
return ErrAdminRequired
|
||||||
|
case C.SQLITE_OK:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// authUserDelete can be used to delete a user.
|
||||||
|
//
|
||||||
|
// This function can only be executed by an admin.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authUserDelete(username string) int {
|
||||||
|
// Allocate C Variables
|
||||||
|
cuser := C.CString(username)
|
||||||
|
|
||||||
|
// Free C Variables
|
||||||
|
defer func() {
|
||||||
|
C.free(unsafe.Pointer(cuser))
|
||||||
|
}()
|
||||||
|
|
||||||
|
return int(C._sqlite3_user_delete(c.db, cuser))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthEnabled checks if the database is protected by user authentication
|
||||||
|
func (c *SQLiteConn) AuthEnabled() (exists bool) {
|
||||||
|
rv := c.authEnabled()
|
||||||
|
if rv == 1 {
|
||||||
|
exists = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// authEnabled perform the actual check for user authentication.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 - Disabled
|
||||||
|
// 1 - Enabled
|
||||||
|
func (c *SQLiteConn) authEnabled() int {
|
||||||
|
return int(C._sqlite3_auth_enabled(c.db))
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOF
|
152
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_userauth_omit.go
generated
vendored
Normal file
152
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_userauth_omit.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !sqlite_userauth
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"C"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Authenticate will perform an authentication of the provided username
|
||||||
|
// and password against the database.
|
||||||
|
//
|
||||||
|
// If a database contains the SQLITE_USER table, then the
|
||||||
|
// call to Authenticate must be invoked with an
|
||||||
|
// appropriate username and password prior to enable read and write
|
||||||
|
//access to the database.
|
||||||
|
//
|
||||||
|
// Return SQLITE_OK on success or SQLITE_ERROR if the username/password
|
||||||
|
// combination is incorrect or unknown.
|
||||||
|
//
|
||||||
|
// If the SQLITE_USER table is not present in the database file, then
|
||||||
|
// this interface is a harmless no-op returnning SQLITE_OK.
|
||||||
|
func (c *SQLiteConn) Authenticate(username, password string) error {
|
||||||
|
// NOOP
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// authenticate provides the actual authentication to SQLite.
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authenticate(username, password string) int {
|
||||||
|
// NOOP
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthUserAdd can be used (by an admin user only)
|
||||||
|
// to create a new user. When called on a no-authentication-required
|
||||||
|
// database, this routine converts the database into an authentication-
|
||||||
|
// required database, automatically makes the added user an
|
||||||
|
// administrator, and logs in the current connection as that user.
|
||||||
|
// The AuthUserAdd only works for the "main" database, not
|
||||||
|
// for any ATTACH-ed databases. Any call to AuthUserAdd by a
|
||||||
|
// non-admin user results in an error.
|
||||||
|
func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
|
||||||
|
// NOOP
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// authUserAdd enables the User Authentication if not enabled.
|
||||||
|
// Otherwise it will add a user.
|
||||||
|
//
|
||||||
|
// When user authentication is already enabled then this function
|
||||||
|
// can only be called by an admin.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
|
||||||
|
// NOOP
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthUserChange can be used to change a users
|
||||||
|
// login credentials or admin privilege. Any user can change their own
|
||||||
|
// login credentials. Only an admin user can change another users login
|
||||||
|
// credentials or admin privilege setting. No user may change their own
|
||||||
|
// admin privilege setting.
|
||||||
|
func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
|
||||||
|
// NOOP
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// authUserChange allows to modify a user.
|
||||||
|
// Users can change their own password.
|
||||||
|
//
|
||||||
|
// Only admins can change passwords for other users
|
||||||
|
// and modify the admin flag.
|
||||||
|
//
|
||||||
|
// The admin flag of the current logged in user cannot be changed.
|
||||||
|
// THis ensures that their is always an admin.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
|
||||||
|
// NOOP
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthUserDelete can be used (by an admin user only)
|
||||||
|
// to delete a user. The currently logged-in user cannot be deleted,
|
||||||
|
// which guarantees that there is always an admin user and hence that
|
||||||
|
// the database cannot be converted into a no-authentication-required
|
||||||
|
// database.
|
||||||
|
func (c *SQLiteConn) AuthUserDelete(username string) error {
|
||||||
|
// NOOP
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// authUserDelete can be used to delete a user.
|
||||||
|
//
|
||||||
|
// This function can only be executed by an admin.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// C.SQLITE_OK (0)
|
||||||
|
// C.SQLITE_ERROR (1)
|
||||||
|
// C.SQLITE_AUTH (23)
|
||||||
|
func (c *SQLiteConn) authUserDelete(username string) int {
|
||||||
|
// NOOP
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthEnabled checks if the database is protected by user authentication
|
||||||
|
func (c *SQLiteConn) AuthEnabled() (exists bool) {
|
||||||
|
// NOOP
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// authEnabled perform the actual check for user authentication.
|
||||||
|
//
|
||||||
|
// This is not exported for usage in Go.
|
||||||
|
// It is however exported for usage within SQL by the user.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 - Disabled
|
||||||
|
// 1 - Enabled
|
||||||
|
func (c *SQLiteConn) authEnabled() int {
|
||||||
|
// NOOP
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOF
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vacuum_full.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vacuum_full.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_vacuum_full
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_DEFAULT_AUTOVACUUM=1
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vacuum_incr.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vacuum_incr.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_vacuum_incr
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -DSQLITE_DEFAULT_AUTOVACUUM=2
|
||||||
|
#cgo LDFLAGS: -lm
|
||||||
|
*/
|
||||||
|
import "C"
|
709
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go
generated
vendored
Normal file
709
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go
generated
vendored
Normal file
|
@ -0,0 +1,709 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_vtable vtable
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -std=gnu99
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_RTREE
|
||||||
|
#cgo CFLAGS: -DSQLITE_THREADSAFE
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3_PARENTHESIS
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_FTS4_UNICODE61
|
||||||
|
#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
|
||||||
|
#cgo CFLAGS: -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||||
|
#cgo CFLAGS: -Wno-deprecated-declarations
|
||||||
|
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
static inline char *_sqlite3_mprintf(char *zFormat, char *arg) {
|
||||||
|
return sqlite3_mprintf(zFormat, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct goVTab goVTab;
|
||||||
|
|
||||||
|
struct goVTab {
|
||||||
|
sqlite3_vtab base;
|
||||||
|
void *vTab;
|
||||||
|
};
|
||||||
|
|
||||||
|
uintptr_t goMInit(void *db, void *pAux, int argc, char **argv, char **pzErr, int isCreate);
|
||||||
|
|
||||||
|
static int cXInit(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr, int isCreate) {
|
||||||
|
void *vTab = (void *)goMInit(db, pAux, argc, (char**)argv, pzErr, isCreate);
|
||||||
|
if (!vTab || *pzErr) {
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
goVTab *pvTab = (goVTab *)sqlite3_malloc(sizeof(goVTab));
|
||||||
|
if (!pvTab) {
|
||||||
|
*pzErr = sqlite3_mprintf("%s", "Out of memory");
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
memset(pvTab, 0, sizeof(goVTab));
|
||||||
|
pvTab->vTab = vTab;
|
||||||
|
|
||||||
|
*ppVTab = (sqlite3_vtab *)pvTab;
|
||||||
|
*pzErr = 0;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int cXCreate(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) {
|
||||||
|
return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 1);
|
||||||
|
}
|
||||||
|
static inline int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) {
|
||||||
|
return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVBestIndex(void *pVTab, void *icp);
|
||||||
|
|
||||||
|
static inline int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) {
|
||||||
|
char *pzErr = goVBestIndex(((goVTab*)pVTab)->vTab, info);
|
||||||
|
if (pzErr) {
|
||||||
|
if (pVTab->zErrMsg)
|
||||||
|
sqlite3_free(pVTab->zErrMsg);
|
||||||
|
pVTab->zErrMsg = pzErr;
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVRelease(void *pVTab, int isDestroy);
|
||||||
|
|
||||||
|
static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) {
|
||||||
|
char *pzErr = goVRelease(((goVTab*)pVTab)->vTab, isDestroy);
|
||||||
|
if (pzErr) {
|
||||||
|
if (pVTab->zErrMsg)
|
||||||
|
sqlite3_free(pVTab->zErrMsg);
|
||||||
|
pVTab->zErrMsg = pzErr;
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
if (pVTab->zErrMsg)
|
||||||
|
sqlite3_free(pVTab->zErrMsg);
|
||||||
|
sqlite3_free(pVTab);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int cXDisconnect(sqlite3_vtab *pVTab) {
|
||||||
|
return cXRelease(pVTab, 0);
|
||||||
|
}
|
||||||
|
static inline int cXDestroy(sqlite3_vtab *pVTab) {
|
||||||
|
return cXRelease(pVTab, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct goVTabCursor goVTabCursor;
|
||||||
|
|
||||||
|
struct goVTabCursor {
|
||||||
|
sqlite3_vtab_cursor base;
|
||||||
|
void *vTabCursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
uintptr_t goVOpen(void *pVTab, char **pzErr);
|
||||||
|
|
||||||
|
static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
|
||||||
|
void *vTabCursor = (void *)goVOpen(((goVTab*)pVTab)->vTab, &(pVTab->zErrMsg));
|
||||||
|
goVTabCursor *pCursor = (goVTabCursor *)sqlite3_malloc(sizeof(goVTabCursor));
|
||||||
|
if (!pCursor) {
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
memset(pCursor, 0, sizeof(goVTabCursor));
|
||||||
|
pCursor->vTabCursor = vTabCursor;
|
||||||
|
*ppCursor = (sqlite3_vtab_cursor *)pCursor;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setErrMsg(sqlite3_vtab_cursor *pCursor, char *pzErr) {
|
||||||
|
if (pCursor->pVtab->zErrMsg)
|
||||||
|
sqlite3_free(pCursor->pVtab->zErrMsg);
|
||||||
|
pCursor->pVtab->zErrMsg = pzErr;
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVClose(void *pCursor);
|
||||||
|
|
||||||
|
static int cXClose(sqlite3_vtab_cursor *pCursor) {
|
||||||
|
char *pzErr = goVClose(((goVTabCursor*)pCursor)->vTabCursor);
|
||||||
|
if (pzErr) {
|
||||||
|
return setErrMsg(pCursor, pzErr);
|
||||||
|
}
|
||||||
|
sqlite3_free(pCursor);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVFilter(void *pCursor, int idxNum, char* idxName, int argc, sqlite3_value **argv);
|
||||||
|
|
||||||
|
static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) {
|
||||||
|
char *pzErr = goVFilter(((goVTabCursor*)pCursor)->vTabCursor, idxNum, (char*)idxStr, argc, argv);
|
||||||
|
if (pzErr) {
|
||||||
|
return setErrMsg(pCursor, pzErr);
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVNext(void *pCursor);
|
||||||
|
|
||||||
|
static int cXNext(sqlite3_vtab_cursor *pCursor) {
|
||||||
|
char *pzErr = goVNext(((goVTabCursor*)pCursor)->vTabCursor);
|
||||||
|
if (pzErr) {
|
||||||
|
return setErrMsg(pCursor, pzErr);
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int goVEof(void *pCursor);
|
||||||
|
|
||||||
|
static inline int cXEof(sqlite3_vtab_cursor *pCursor) {
|
||||||
|
return goVEof(((goVTabCursor*)pCursor)->vTabCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVColumn(void *pCursor, void *cp, int col);
|
||||||
|
|
||||||
|
static int cXColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i) {
|
||||||
|
char *pzErr = goVColumn(((goVTabCursor*)pCursor)->vTabCursor, ctx, i);
|
||||||
|
if (pzErr) {
|
||||||
|
return setErrMsg(pCursor, pzErr);
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVRowid(void *pCursor, sqlite3_int64 *pRowid);
|
||||||
|
|
||||||
|
static int cXRowid(sqlite3_vtab_cursor *pCursor, sqlite3_int64 *pRowid) {
|
||||||
|
char *pzErr = goVRowid(((goVTabCursor*)pCursor)->vTabCursor, pRowid);
|
||||||
|
if (pzErr) {
|
||||||
|
return setErrMsg(pCursor, pzErr);
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* goVUpdate(void *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid);
|
||||||
|
|
||||||
|
static int cXUpdate(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid) {
|
||||||
|
char *pzErr = goVUpdate(((goVTab*)pVTab)->vTab, argc, argv, pRowid);
|
||||||
|
if (pzErr) {
|
||||||
|
if (pVTab->zErrMsg)
|
||||||
|
sqlite3_free(pVTab->zErrMsg);
|
||||||
|
pVTab->zErrMsg = pzErr;
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sqlite3_module goModule = {
|
||||||
|
0, // iVersion
|
||||||
|
cXCreate, // xCreate - create a table
|
||||||
|
cXConnect, // xConnect - connect to an existing table
|
||||||
|
cXBestIndex, // xBestIndex - Determine search strategy
|
||||||
|
cXDisconnect, // xDisconnect - Disconnect from a table
|
||||||
|
cXDestroy, // xDestroy - Drop a table
|
||||||
|
cXOpen, // xOpen - open a cursor
|
||||||
|
cXClose, // xClose - close a cursor
|
||||||
|
cXFilter, // xFilter - configure scan constraints
|
||||||
|
cXNext, // xNext - advance a cursor
|
||||||
|
cXEof, // xEof
|
||||||
|
cXColumn, // xColumn - read data
|
||||||
|
cXRowid, // xRowid - read data
|
||||||
|
cXUpdate, // xUpdate - write data
|
||||||
|
// Not implemented
|
||||||
|
0, // xBegin - begin transaction
|
||||||
|
0, // xSync - sync transaction
|
||||||
|
0, // xCommit - commit transaction
|
||||||
|
0, // xRollback - rollback transaction
|
||||||
|
0, // xFindFunction - function overloading
|
||||||
|
0, // xRename - rename the table
|
||||||
|
0, // xSavepoint
|
||||||
|
0, // xRelease
|
||||||
|
0 // xRollbackTo
|
||||||
|
};
|
||||||
|
|
||||||
|
// See https://sqlite.org/vtab.html#eponymous_only_virtual_tables
|
||||||
|
static sqlite3_module goModuleEponymousOnly = {
|
||||||
|
0, // iVersion
|
||||||
|
0, // xCreate - create a table, which here is null
|
||||||
|
cXConnect, // xConnect - connect to an existing table
|
||||||
|
cXBestIndex, // xBestIndex - Determine search strategy
|
||||||
|
cXDisconnect, // xDisconnect - Disconnect from a table
|
||||||
|
cXDestroy, // xDestroy - Drop a table
|
||||||
|
cXOpen, // xOpen - open a cursor
|
||||||
|
cXClose, // xClose - close a cursor
|
||||||
|
cXFilter, // xFilter - configure scan constraints
|
||||||
|
cXNext, // xNext - advance a cursor
|
||||||
|
cXEof, // xEof
|
||||||
|
cXColumn, // xColumn - read data
|
||||||
|
cXRowid, // xRowid - read data
|
||||||
|
cXUpdate, // xUpdate - write data
|
||||||
|
// Not implemented
|
||||||
|
0, // xBegin - begin transaction
|
||||||
|
0, // xSync - sync transaction
|
||||||
|
0, // xCommit - commit transaction
|
||||||
|
0, // xRollback - rollback transaction
|
||||||
|
0, // xFindFunction - function overloading
|
||||||
|
0, // xRename - rename the table
|
||||||
|
0, // xSavepoint
|
||||||
|
0, // xRelease
|
||||||
|
0 // xRollbackTo
|
||||||
|
};
|
||||||
|
|
||||||
|
void goMDestroy(void*);
|
||||||
|
|
||||||
|
static int _sqlite3_create_module(sqlite3 *db, const char *zName, uintptr_t pClientData) {
|
||||||
|
return sqlite3_create_module_v2(db, zName, &goModule, (void*) pClientData, goMDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sqlite3_create_module_eponymous_only(sqlite3 *db, const char *zName, uintptr_t pClientData) {
|
||||||
|
return sqlite3_create_module_v2(db, zName, &goModuleEponymousOnly, (void*) pClientData, goMDestroy);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sqliteModule struct {
|
||||||
|
c *SQLiteConn
|
||||||
|
name string
|
||||||
|
module Module
|
||||||
|
}
|
||||||
|
|
||||||
|
type sqliteVTab struct {
|
||||||
|
module *sqliteModule
|
||||||
|
vTab VTab
|
||||||
|
}
|
||||||
|
|
||||||
|
type sqliteVTabCursor struct {
|
||||||
|
vTab *sqliteVTab
|
||||||
|
vTabCursor VTabCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Op is type of operations.
|
||||||
|
type Op uint8
|
||||||
|
|
||||||
|
// Op mean identity of operations.
|
||||||
|
const (
|
||||||
|
OpEQ Op = 2
|
||||||
|
OpGT = 4
|
||||||
|
OpLE = 8
|
||||||
|
OpLT = 16
|
||||||
|
OpGE = 32
|
||||||
|
OpMATCH = 64
|
||||||
|
OpLIKE = 65 /* 3.10.0 and later only */
|
||||||
|
OpGLOB = 66 /* 3.10.0 and later only */
|
||||||
|
OpREGEXP = 67 /* 3.10.0 and later only */
|
||||||
|
OpScanUnique = 1 /* Scan visits at most 1 row */
|
||||||
|
)
|
||||||
|
|
||||||
|
// InfoConstraint give information of constraint.
|
||||||
|
type InfoConstraint struct {
|
||||||
|
Column int
|
||||||
|
Op Op
|
||||||
|
Usable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// InfoOrderBy give information of order-by.
|
||||||
|
type InfoOrderBy struct {
|
||||||
|
Column int
|
||||||
|
Desc bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraints(info *C.sqlite3_index_info) []InfoConstraint {
|
||||||
|
slice := *(*[]C.struct_sqlite3_index_constraint)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Data: uintptr(unsafe.Pointer(info.aConstraint)),
|
||||||
|
Len: int(info.nConstraint),
|
||||||
|
Cap: int(info.nConstraint),
|
||||||
|
}))
|
||||||
|
|
||||||
|
cst := make([]InfoConstraint, 0, len(slice))
|
||||||
|
for _, c := range slice {
|
||||||
|
var usable bool
|
||||||
|
if c.usable > 0 {
|
||||||
|
usable = true
|
||||||
|
}
|
||||||
|
cst = append(cst, InfoConstraint{
|
||||||
|
Column: int(c.iColumn),
|
||||||
|
Op: Op(c.op),
|
||||||
|
Usable: usable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return cst
|
||||||
|
}
|
||||||
|
|
||||||
|
func orderBys(info *C.sqlite3_index_info) []InfoOrderBy {
|
||||||
|
slice := *(*[]C.struct_sqlite3_index_orderby)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Data: uintptr(unsafe.Pointer(info.aOrderBy)),
|
||||||
|
Len: int(info.nOrderBy),
|
||||||
|
Cap: int(info.nOrderBy),
|
||||||
|
}))
|
||||||
|
|
||||||
|
ob := make([]InfoOrderBy, 0, len(slice))
|
||||||
|
for _, c := range slice {
|
||||||
|
var desc bool
|
||||||
|
if c.desc > 0 {
|
||||||
|
desc = true
|
||||||
|
}
|
||||||
|
ob = append(ob, InfoOrderBy{
|
||||||
|
Column: int(c.iColumn),
|
||||||
|
Desc: desc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ob
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexResult is a Go struct representation of what eventually ends up in the
|
||||||
|
// output fields for `sqlite3_index_info`
|
||||||
|
// See: https://www.sqlite.org/c3ref/index_info.html
|
||||||
|
type IndexResult struct {
|
||||||
|
Used []bool // aConstraintUsage
|
||||||
|
IdxNum int
|
||||||
|
IdxStr string
|
||||||
|
AlreadyOrdered bool // orderByConsumed
|
||||||
|
EstimatedCost float64
|
||||||
|
EstimatedRows float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// mPrintf is a utility wrapper around sqlite3_mprintf
|
||||||
|
func mPrintf(format, arg string) *C.char {
|
||||||
|
cf := C.CString(format)
|
||||||
|
defer C.free(unsafe.Pointer(cf))
|
||||||
|
ca := C.CString(arg)
|
||||||
|
defer C.free(unsafe.Pointer(ca))
|
||||||
|
return C._sqlite3_mprintf(cf, ca)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goMInit
|
||||||
|
func goMInit(db, pClientData unsafe.Pointer, argc C.int, argv **C.char, pzErr **C.char, isCreate C.int) C.uintptr_t {
|
||||||
|
m := lookupHandle(pClientData).(*sqliteModule)
|
||||||
|
if m.c.db != (*C.sqlite3)(db) {
|
||||||
|
*pzErr = mPrintf("%s", "Inconsistent db handles")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
args := make([]string, argc)
|
||||||
|
var A []*C.char
|
||||||
|
slice := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(argv)), Len: int(argc), Cap: int(argc)}
|
||||||
|
a := reflect.NewAt(reflect.TypeOf(A), unsafe.Pointer(&slice)).Elem().Interface()
|
||||||
|
for i, s := range a.([]*C.char) {
|
||||||
|
args[i] = C.GoString(s)
|
||||||
|
}
|
||||||
|
var vTab VTab
|
||||||
|
var err error
|
||||||
|
if isCreate == 1 {
|
||||||
|
vTab, err = m.module.Create(m.c, args)
|
||||||
|
} else {
|
||||||
|
vTab, err = m.module.Connect(m.c, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
*pzErr = mPrintf("%s", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
vt := sqliteVTab{m, vTab}
|
||||||
|
*pzErr = nil
|
||||||
|
return C.uintptr_t(uintptr(newHandle(m.c, &vt)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVRelease
|
||||||
|
func goVRelease(pVTab unsafe.Pointer, isDestroy C.int) *C.char {
|
||||||
|
vt := lookupHandle(pVTab).(*sqliteVTab)
|
||||||
|
var err error
|
||||||
|
if isDestroy == 1 {
|
||||||
|
err = vt.vTab.Destroy()
|
||||||
|
} else {
|
||||||
|
err = vt.vTab.Disconnect()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVOpen
|
||||||
|
func goVOpen(pVTab unsafe.Pointer, pzErr **C.char) C.uintptr_t {
|
||||||
|
vt := lookupHandle(pVTab).(*sqliteVTab)
|
||||||
|
vTabCursor, err := vt.vTab.Open()
|
||||||
|
if err != nil {
|
||||||
|
*pzErr = mPrintf("%s", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
vtc := sqliteVTabCursor{vt, vTabCursor}
|
||||||
|
*pzErr = nil
|
||||||
|
return C.uintptr_t(uintptr(newHandle(vt.module.c, &vtc)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVBestIndex
|
||||||
|
func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char {
|
||||||
|
vt := lookupHandle(pVTab).(*sqliteVTab)
|
||||||
|
info := (*C.sqlite3_index_info)(icp)
|
||||||
|
csts := constraints(info)
|
||||||
|
res, err := vt.vTab.BestIndex(csts, orderBys(info))
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
if len(res.Used) != len(csts) {
|
||||||
|
return mPrintf("Result.Used != expected value", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a pointer to constraint_usage struct so we can update in place.
|
||||||
|
|
||||||
|
slice := *(*[]C.struct_sqlite3_index_constraint_usage)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Data: uintptr(unsafe.Pointer(info.aConstraintUsage)),
|
||||||
|
Len: int(info.nConstraint),
|
||||||
|
Cap: int(info.nConstraint),
|
||||||
|
}))
|
||||||
|
index := 1
|
||||||
|
for i := range slice {
|
||||||
|
if res.Used[i] {
|
||||||
|
slice[i].argvIndex = C.int(index)
|
||||||
|
slice[i].omit = C.uchar(1)
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.idxNum = C.int(res.IdxNum)
|
||||||
|
idxStr := C.CString(res.IdxStr)
|
||||||
|
defer C.free(unsafe.Pointer(idxStr))
|
||||||
|
info.idxStr = idxStr
|
||||||
|
info.needToFreeIdxStr = C.int(0)
|
||||||
|
if res.AlreadyOrdered {
|
||||||
|
info.orderByConsumed = C.int(1)
|
||||||
|
}
|
||||||
|
info.estimatedCost = C.double(res.EstimatedCost)
|
||||||
|
info.estimatedRows = C.sqlite3_int64(res.EstimatedRows)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVClose
|
||||||
|
func goVClose(pCursor unsafe.Pointer) *C.char {
|
||||||
|
vtc := lookupHandle(pCursor).(*sqliteVTabCursor)
|
||||||
|
err := vtc.vTabCursor.Close()
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goMDestroy
|
||||||
|
func goMDestroy(pClientData unsafe.Pointer) {
|
||||||
|
m := lookupHandle(pClientData).(*sqliteModule)
|
||||||
|
m.module.DestroyModule()
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVFilter
|
||||||
|
func goVFilter(pCursor unsafe.Pointer, idxNum C.int, idxName *C.char, argc C.int, argv **C.sqlite3_value) *C.char {
|
||||||
|
vtc := lookupHandle(pCursor).(*sqliteVTabCursor)
|
||||||
|
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
|
||||||
|
vals := make([]interface{}, 0, argc)
|
||||||
|
for _, v := range args {
|
||||||
|
conv, err := callbackArgGeneric(v)
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
vals = append(vals, conv.Interface())
|
||||||
|
}
|
||||||
|
err := vtc.vTabCursor.Filter(int(idxNum), C.GoString(idxName), vals)
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVNext
|
||||||
|
func goVNext(pCursor unsafe.Pointer) *C.char {
|
||||||
|
vtc := lookupHandle(pCursor).(*sqliteVTabCursor)
|
||||||
|
err := vtc.vTabCursor.Next()
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVEof
|
||||||
|
func goVEof(pCursor unsafe.Pointer) C.int {
|
||||||
|
vtc := lookupHandle(pCursor).(*sqliteVTabCursor)
|
||||||
|
err := vtc.vTabCursor.EOF()
|
||||||
|
if err {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVColumn
|
||||||
|
func goVColumn(pCursor, cp unsafe.Pointer, col C.int) *C.char {
|
||||||
|
vtc := lookupHandle(pCursor).(*sqliteVTabCursor)
|
||||||
|
c := (*SQLiteContext)(cp)
|
||||||
|
err := vtc.vTabCursor.Column(c, int(col))
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVRowid
|
||||||
|
func goVRowid(pCursor unsafe.Pointer, pRowid *C.sqlite3_int64) *C.char {
|
||||||
|
vtc := lookupHandle(pCursor).(*sqliteVTabCursor)
|
||||||
|
rowid, err := vtc.vTabCursor.Rowid()
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
*pRowid = C.sqlite3_int64(rowid)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goVUpdate
|
||||||
|
func goVUpdate(pVTab unsafe.Pointer, argc C.int, argv **C.sqlite3_value, pRowid *C.sqlite3_int64) *C.char {
|
||||||
|
vt := lookupHandle(pVTab).(*sqliteVTab)
|
||||||
|
|
||||||
|
var tname string
|
||||||
|
if n, ok := vt.vTab.(interface {
|
||||||
|
TableName() string
|
||||||
|
}); ok {
|
||||||
|
tname = n.TableName() + " "
|
||||||
|
}
|
||||||
|
|
||||||
|
err := fmt.Errorf("virtual %s table %sis read-only", vt.module.name, tname)
|
||||||
|
if v, ok := vt.vTab.(VTabUpdater); ok {
|
||||||
|
// convert argv
|
||||||
|
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
|
||||||
|
vals := make([]interface{}, 0, argc)
|
||||||
|
for _, v := range args {
|
||||||
|
conv, err := callbackArgGeneric(v)
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// work around for SQLITE_NULL
|
||||||
|
x := conv.Interface()
|
||||||
|
if z, ok := x.([]byte); ok && z == nil {
|
||||||
|
x = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vals = append(vals, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case argc == 1:
|
||||||
|
err = v.Delete(vals[0])
|
||||||
|
|
||||||
|
case argc > 1 && vals[0] == nil:
|
||||||
|
var id int64
|
||||||
|
id, err = v.Insert(vals[1], vals[2:])
|
||||||
|
if err == nil {
|
||||||
|
*pRowid = C.sqlite3_int64(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
case argc > 1:
|
||||||
|
err = v.Update(vals[1], vals[2:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return mPrintf("%s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module is a "virtual table module", it defines the implementation of a
|
||||||
|
// virtual tables. See: http://sqlite.org/c3ref/module.html
|
||||||
|
type Module interface {
|
||||||
|
// http://sqlite.org/vtab.html#xcreate
|
||||||
|
Create(c *SQLiteConn, args []string) (VTab, error)
|
||||||
|
// http://sqlite.org/vtab.html#xconnect
|
||||||
|
Connect(c *SQLiteConn, args []string) (VTab, error)
|
||||||
|
// http://sqlite.org/c3ref/create_module.html
|
||||||
|
DestroyModule()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EponymousOnlyModule is a "virtual table module" (as above), but
|
||||||
|
// for defining "eponymous only" virtual tables See: https://sqlite.org/vtab.html#eponymous_only_virtual_tables
|
||||||
|
type EponymousOnlyModule interface {
|
||||||
|
Module
|
||||||
|
EponymousOnlyModule()
|
||||||
|
}
|
||||||
|
|
||||||
|
// VTab describes a particular instance of the virtual table.
|
||||||
|
// See: http://sqlite.org/c3ref/vtab.html
|
||||||
|
type VTab interface {
|
||||||
|
// http://sqlite.org/vtab.html#xbestindex
|
||||||
|
BestIndex([]InfoConstraint, []InfoOrderBy) (*IndexResult, error)
|
||||||
|
// http://sqlite.org/vtab.html#xdisconnect
|
||||||
|
Disconnect() error
|
||||||
|
// http://sqlite.org/vtab.html#sqlite3_module.xDestroy
|
||||||
|
Destroy() error
|
||||||
|
// http://sqlite.org/vtab.html#xopen
|
||||||
|
Open() (VTabCursor, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VTabUpdater is a type that allows a VTab to be inserted, updated, or
|
||||||
|
// deleted.
|
||||||
|
// See: https://sqlite.org/vtab.html#xupdate
|
||||||
|
type VTabUpdater interface {
|
||||||
|
Delete(interface{}) error
|
||||||
|
Insert(interface{}, []interface{}) (int64, error)
|
||||||
|
Update(interface{}, []interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// VTabCursor describes cursors that point into the virtual table and are used
|
||||||
|
// to loop through the virtual table. See: http://sqlite.org/c3ref/vtab_cursor.html
|
||||||
|
type VTabCursor interface {
|
||||||
|
// http://sqlite.org/vtab.html#xclose
|
||||||
|
Close() error
|
||||||
|
// http://sqlite.org/vtab.html#xfilter
|
||||||
|
Filter(idxNum int, idxStr string, vals []interface{}) error
|
||||||
|
// http://sqlite.org/vtab.html#xnext
|
||||||
|
Next() error
|
||||||
|
// http://sqlite.org/vtab.html#xeof
|
||||||
|
EOF() bool
|
||||||
|
// http://sqlite.org/vtab.html#xcolumn
|
||||||
|
Column(c *SQLiteContext, col int) error
|
||||||
|
// http://sqlite.org/vtab.html#xrowid
|
||||||
|
Rowid() (int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeclareVTab declares the Schema of a virtual table.
|
||||||
|
// See: http://sqlite.org/c3ref/declare_vtab.html
|
||||||
|
func (c *SQLiteConn) DeclareVTab(sql string) error {
|
||||||
|
zSQL := C.CString(sql)
|
||||||
|
defer C.free(unsafe.Pointer(zSQL))
|
||||||
|
rv := C.sqlite3_declare_vtab(c.db, zSQL)
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateModule registers a virtual table implementation.
|
||||||
|
// See: http://sqlite.org/c3ref/create_module.html
|
||||||
|
func (c *SQLiteConn) CreateModule(moduleName string, module Module) error {
|
||||||
|
mname := C.CString(moduleName)
|
||||||
|
defer C.free(unsafe.Pointer(mname))
|
||||||
|
udm := sqliteModule{c, moduleName, module}
|
||||||
|
switch module.(type) {
|
||||||
|
case EponymousOnlyModule:
|
||||||
|
rv := C._sqlite3_create_module_eponymous_only(c.db, mname, C.uintptr_t(uintptr(newHandle(c, &udm))))
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case Module:
|
||||||
|
rv := C._sqlite3_create_module(c.db, mname, C.uintptr_t(uintptr(newHandle(c, &udm))))
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
17
vendor/github.com/mattn/go-sqlite3/sqlite3_other.go
generated
vendored
Normal file
17
vendor/github.com/mattn/go-sqlite3/sqlite3_other.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -I.
|
||||||
|
#cgo linux LDFLAGS: -ldl
|
||||||
|
#cgo linux,ppc LDFLAGS: -lpthread
|
||||||
|
#cgo linux,ppc64 LDFLAGS: -lpthread
|
||||||
|
#cgo linux,ppc64le LDFLAGS: -lpthread
|
||||||
|
*/
|
||||||
|
import "C"
|
14
vendor/github.com/mattn/go-sqlite3/sqlite3_solaris.go
generated
vendored
Normal file
14
vendor/github.com/mattn/go-sqlite3/sqlite3_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -D__EXTENSIONS__=1
|
||||||
|
#cgo LDFLAGS: -lc
|
||||||
|
*/
|
||||||
|
import "C"
|
287
vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go
generated
vendored
Normal file
287
vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go
generated
vendored
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build sqlite_trace trace
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int traceCallbackTrampoline(unsigned int traceEventCode, void *ctx, void *p, void *x);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Trace... constants identify the possible events causing callback invocation.
|
||||||
|
// Values are same as the corresponding SQLite Trace Event Codes.
|
||||||
|
const (
|
||||||
|
TraceStmt = uint32(C.SQLITE_TRACE_STMT)
|
||||||
|
TraceProfile = uint32(C.SQLITE_TRACE_PROFILE)
|
||||||
|
TraceRow = uint32(C.SQLITE_TRACE_ROW)
|
||||||
|
TraceClose = uint32(C.SQLITE_TRACE_CLOSE)
|
||||||
|
)
|
||||||
|
|
||||||
|
type TraceInfo struct {
|
||||||
|
// Pack together the shorter fields, to keep the struct smaller.
|
||||||
|
// On a 64-bit machine there would be padding
|
||||||
|
// between EventCode and ConnHandle; having AutoCommit here is "free":
|
||||||
|
EventCode uint32
|
||||||
|
AutoCommit bool
|
||||||
|
ConnHandle uintptr
|
||||||
|
|
||||||
|
// Usually filled, unless EventCode = TraceClose = SQLITE_TRACE_CLOSE:
|
||||||
|
// identifier for a prepared statement:
|
||||||
|
StmtHandle uintptr
|
||||||
|
|
||||||
|
// Two strings filled when EventCode = TraceStmt = SQLITE_TRACE_STMT:
|
||||||
|
// (1) either the unexpanded SQL text of the prepared statement, or
|
||||||
|
// an SQL comment that indicates the invocation of a trigger;
|
||||||
|
// (2) expanded SQL, if requested and if (1) is not an SQL comment.
|
||||||
|
StmtOrTrigger string
|
||||||
|
ExpandedSQL string // only if requested (TraceConfig.WantExpandedSQL = true)
|
||||||
|
|
||||||
|
// filled when EventCode = TraceProfile = SQLITE_TRACE_PROFILE:
|
||||||
|
// estimated number of nanoseconds that the prepared statement took to run:
|
||||||
|
RunTimeNanosec int64
|
||||||
|
|
||||||
|
DBError Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraceUserCallback gives the signature for a trace function
|
||||||
|
// provided by the user (Go application programmer).
|
||||||
|
// SQLite 3.14 documentation (as of September 2, 2016)
|
||||||
|
// for SQL Trace Hook = sqlite3_trace_v2():
|
||||||
|
// The integer return value from the callback is currently ignored,
|
||||||
|
// though this may change in future releases. Callback implementations
|
||||||
|
// should return zero to ensure future compatibility.
|
||||||
|
type TraceUserCallback func(TraceInfo) int
|
||||||
|
|
||||||
|
type TraceConfig struct {
|
||||||
|
Callback TraceUserCallback
|
||||||
|
EventMask uint32
|
||||||
|
WantExpandedSQL bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillDBError(dbErr *Error, db *C.sqlite3) {
|
||||||
|
// See SQLiteConn.lastError(), in file 'sqlite3.go' at the time of writing (Sept 5, 2016)
|
||||||
|
dbErr.Code = ErrNo(C.sqlite3_errcode(db))
|
||||||
|
dbErr.ExtendedCode = ErrNoExtended(C.sqlite3_extended_errcode(db))
|
||||||
|
dbErr.err = C.GoString(C.sqlite3_errmsg(db))
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillExpandedSQL(info *TraceInfo, db *C.sqlite3, pStmt unsafe.Pointer) {
|
||||||
|
if pStmt == nil {
|
||||||
|
panic("No SQLite statement pointer in P arg of trace_v2 callback")
|
||||||
|
}
|
||||||
|
|
||||||
|
expSQLiteCStr := C.sqlite3_expanded_sql((*C.sqlite3_stmt)(pStmt))
|
||||||
|
defer C.sqlite3_free(unsafe.Pointer(expSQLiteCStr))
|
||||||
|
if expSQLiteCStr == nil {
|
||||||
|
fillDBError(&info.DBError, db)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
info.ExpandedSQL = C.GoString(expSQLiteCStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export traceCallbackTrampoline
|
||||||
|
func traceCallbackTrampoline(
|
||||||
|
traceEventCode C.uint,
|
||||||
|
// Parameter named 'C' in SQLite docs = Context given at registration:
|
||||||
|
ctx unsafe.Pointer,
|
||||||
|
// Parameter named 'P' in SQLite docs (Primary event data?):
|
||||||
|
p unsafe.Pointer,
|
||||||
|
// Parameter named 'X' in SQLite docs (eXtra event data?):
|
||||||
|
xValue unsafe.Pointer) C.int {
|
||||||
|
|
||||||
|
eventCode := uint32(traceEventCode)
|
||||||
|
|
||||||
|
if ctx == nil {
|
||||||
|
panic(fmt.Sprintf("No context (ev 0x%x)", traceEventCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
contextDB := (*C.sqlite3)(ctx)
|
||||||
|
connHandle := uintptr(ctx)
|
||||||
|
|
||||||
|
var traceConf TraceConfig
|
||||||
|
var found bool
|
||||||
|
if eventCode == TraceClose {
|
||||||
|
// clean up traceMap: 'pop' means get and delete
|
||||||
|
traceConf, found = popTraceMapping(connHandle)
|
||||||
|
} else {
|
||||||
|
traceConf, found = lookupTraceMapping(connHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
panic(fmt.Sprintf("Mapping not found for handle 0x%x (ev 0x%x)",
|
||||||
|
connHandle, eventCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
var info TraceInfo
|
||||||
|
|
||||||
|
info.EventCode = eventCode
|
||||||
|
info.AutoCommit = (int(C.sqlite3_get_autocommit(contextDB)) != 0)
|
||||||
|
info.ConnHandle = connHandle
|
||||||
|
|
||||||
|
switch eventCode {
|
||||||
|
case TraceStmt:
|
||||||
|
info.StmtHandle = uintptr(p)
|
||||||
|
|
||||||
|
var xStr string
|
||||||
|
if xValue != nil {
|
||||||
|
xStr = C.GoString((*C.char)(xValue))
|
||||||
|
}
|
||||||
|
info.StmtOrTrigger = xStr
|
||||||
|
if !strings.HasPrefix(xStr, "--") {
|
||||||
|
// Not SQL comment, therefore the current event
|
||||||
|
// is not related to a trigger.
|
||||||
|
// The user might want to receive the expanded SQL;
|
||||||
|
// let's check:
|
||||||
|
if traceConf.WantExpandedSQL {
|
||||||
|
fillExpandedSQL(&info, contextDB, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case TraceProfile:
|
||||||
|
info.StmtHandle = uintptr(p)
|
||||||
|
|
||||||
|
if xValue == nil {
|
||||||
|
panic("NULL pointer in X arg of trace_v2 callback for SQLITE_TRACE_PROFILE event")
|
||||||
|
}
|
||||||
|
|
||||||
|
info.RunTimeNanosec = *(*int64)(xValue)
|
||||||
|
|
||||||
|
// sample the error //TODO: is it safe? is it useful?
|
||||||
|
fillDBError(&info.DBError, contextDB)
|
||||||
|
|
||||||
|
case TraceRow:
|
||||||
|
info.StmtHandle = uintptr(p)
|
||||||
|
|
||||||
|
case TraceClose:
|
||||||
|
handle := uintptr(p)
|
||||||
|
if handle != info.ConnHandle {
|
||||||
|
panic(fmt.Sprintf("Different conn handle 0x%x (expected 0x%x) in SQLITE_TRACE_CLOSE event.",
|
||||||
|
handle, info.ConnHandle))
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Pass unsupported events to the user callback (if configured);
|
||||||
|
// let the user callback decide whether to panic or ignore them.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not execute user callback when the event was not requested by user!
|
||||||
|
// Remember that the Close event is always selected when
|
||||||
|
// registering this callback trampoline with SQLite --- for cleanup.
|
||||||
|
// In the future there may be more events forced to "selected" in SQLite
|
||||||
|
// for the driver's needs.
|
||||||
|
if traceConf.EventMask&eventCode == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
r := 0
|
||||||
|
if traceConf.Callback != nil {
|
||||||
|
r = traceConf.Callback(info)
|
||||||
|
}
|
||||||
|
return C.int(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type traceMapEntry struct {
|
||||||
|
config TraceConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var traceMapLock sync.Mutex
|
||||||
|
var traceMap = make(map[uintptr]traceMapEntry)
|
||||||
|
|
||||||
|
func addTraceMapping(connHandle uintptr, traceConf TraceConfig) {
|
||||||
|
traceMapLock.Lock()
|
||||||
|
defer traceMapLock.Unlock()
|
||||||
|
|
||||||
|
oldEntryCopy, found := traceMap[connHandle]
|
||||||
|
if found {
|
||||||
|
panic(fmt.Sprintf("Adding trace config %v: handle 0x%x already registered (%v).",
|
||||||
|
traceConf, connHandle, oldEntryCopy.config))
|
||||||
|
}
|
||||||
|
traceMap[connHandle] = traceMapEntry{config: traceConf}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupTraceMapping(connHandle uintptr) (TraceConfig, bool) {
|
||||||
|
traceMapLock.Lock()
|
||||||
|
defer traceMapLock.Unlock()
|
||||||
|
|
||||||
|
entryCopy, found := traceMap[connHandle]
|
||||||
|
return entryCopy.config, found
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'pop' = get and delete from map before returning the value to the caller
|
||||||
|
func popTraceMapping(connHandle uintptr) (TraceConfig, bool) {
|
||||||
|
traceMapLock.Lock()
|
||||||
|
defer traceMapLock.Unlock()
|
||||||
|
|
||||||
|
entryCopy, found := traceMap[connHandle]
|
||||||
|
if found {
|
||||||
|
delete(traceMap, connHandle)
|
||||||
|
}
|
||||||
|
return entryCopy.config, found
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTrace installs or removes the trace callback for the given database connection.
|
||||||
|
// It's not named 'RegisterTrace' because only one callback can be kept and called.
|
||||||
|
// Calling SetTrace a second time on same database connection
|
||||||
|
// overrides (cancels) any prior callback and all its settings:
|
||||||
|
// event mask, etc.
|
||||||
|
func (c *SQLiteConn) SetTrace(requested *TraceConfig) error {
|
||||||
|
connHandle := uintptr(unsafe.Pointer(c.db))
|
||||||
|
|
||||||
|
_, _ = popTraceMapping(connHandle)
|
||||||
|
|
||||||
|
if requested == nil {
|
||||||
|
// The traceMap entry was deleted already by popTraceMapping():
|
||||||
|
// can disable all events now, no need to watch for TraceClose.
|
||||||
|
err := c.setSQLiteTrace(0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reqCopy := *requested
|
||||||
|
|
||||||
|
// Disable potentially expensive operations
|
||||||
|
// if their result will not be used. We are doing this
|
||||||
|
// just in case the caller provided nonsensical input.
|
||||||
|
if reqCopy.EventMask&TraceStmt == 0 {
|
||||||
|
reqCopy.WantExpandedSQL = false
|
||||||
|
}
|
||||||
|
|
||||||
|
addTraceMapping(connHandle, reqCopy)
|
||||||
|
|
||||||
|
// The callback trampoline function does cleanup on Close event,
|
||||||
|
// regardless of the presence or absence of the user callback.
|
||||||
|
// Therefore it needs the Close event to be selected:
|
||||||
|
actualEventMask := uint(reqCopy.EventMask | TraceClose)
|
||||||
|
err := c.setSQLiteTrace(actualEventMask)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SQLiteConn) setSQLiteTrace(sqliteEventMask uint) error {
|
||||||
|
rv := C.sqlite3_trace_v2(c.db,
|
||||||
|
C.uint(sqliteEventMask),
|
||||||
|
(*[0]byte)(unsafe.Pointer(C.traceCallbackTrampoline)),
|
||||||
|
unsafe.Pointer(c.db)) // Fourth arg is same as first: we are
|
||||||
|
// passing the database connection handle as callback context.
|
||||||
|
|
||||||
|
if rv != C.SQLITE_OK {
|
||||||
|
return c.lastError()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
62
vendor/github.com/mattn/go-sqlite3/sqlite3_type.go
generated
vendored
Normal file
62
vendor/github.com/mattn/go-sqlite3/sqlite3_type.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
#include <sqlite3-binding.h>
|
||||||
|
#else
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ColumnTypeDatabaseTypeName implement RowsColumnTypeDatabaseTypeName.
|
||||||
|
func (rc *SQLiteRows) ColumnTypeDatabaseTypeName(i int) string {
|
||||||
|
return C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (rc *SQLiteRows) ColumnTypeLength(index int) (length int64, ok bool) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *SQLiteRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColumnTypeNullable implement RowsColumnTypeNullable.
|
||||||
|
func (rc *SQLiteRows) ColumnTypeNullable(i int) (nullable, ok bool) {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ColumnTypeScanType implement RowsColumnTypeScanType.
|
||||||
|
func (rc *SQLiteRows) ColumnTypeScanType(i int) reflect.Type {
|
||||||
|
switch C.sqlite3_column_type(rc.s.s, C.int(i)) {
|
||||||
|
case C.SQLITE_INTEGER:
|
||||||
|
switch C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))) {
|
||||||
|
case "timestamp", "datetime", "date":
|
||||||
|
return reflect.TypeOf(time.Time{})
|
||||||
|
case "boolean":
|
||||||
|
return reflect.TypeOf(false)
|
||||||
|
}
|
||||||
|
return reflect.TypeOf(int64(0))
|
||||||
|
case C.SQLITE_FLOAT:
|
||||||
|
return reflect.TypeOf(float64(0))
|
||||||
|
case C.SQLITE_BLOB:
|
||||||
|
return reflect.SliceOf(reflect.TypeOf(byte(0)))
|
||||||
|
case C.SQLITE_NULL:
|
||||||
|
return reflect.TypeOf(nil)
|
||||||
|
case C.SQLITE_TEXT:
|
||||||
|
return reflect.TypeOf("")
|
||||||
|
}
|
||||||
|
return reflect.SliceOf(reflect.TypeOf(byte(0)))
|
||||||
|
}
|
41
vendor/github.com/mattn/go-sqlite3/sqlite3_usleep_windows.go
generated
vendored
Normal file
41
vendor/github.com/mattn/go-sqlite3/sqlite3_usleep_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
// usleep is a function available on *nix based systems.
|
||||||
|
// This function is not present in Windows.
|
||||||
|
// Windows has a sleep function but this works with seconds
|
||||||
|
// and not with microseconds as usleep.
|
||||||
|
//
|
||||||
|
// This code should improve performance on windows because
|
||||||
|
// without the presence of usleep SQLite waits 1 second.
|
||||||
|
//
|
||||||
|
// Source: https://github.com/php/php-src/blob/PHP-5.0/win32/time.c
|
||||||
|
// License: https://github.com/php/php-src/blob/PHP-5.0/LICENSE
|
||||||
|
// Details: https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
void usleep(__int64 usec)
|
||||||
|
{
|
||||||
|
HANDLE timer;
|
||||||
|
LARGE_INTEGER ft;
|
||||||
|
|
||||||
|
// Convert to 100 nanosecond interval, negative value indicates relative time
|
||||||
|
ft.QuadPart = -(10*usec);
|
||||||
|
|
||||||
|
timer = CreateWaitableTimer(NULL, TRUE, NULL);
|
||||||
|
SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
|
||||||
|
WaitForSingleObject(timer, INFINITE);
|
||||||
|
CloseHandle(timer);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// EOF
|
18
vendor/github.com/mattn/go-sqlite3/sqlite3_windows.go
generated
vendored
Normal file
18
vendor/github.com/mattn/go-sqlite3/sqlite3_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -I.
|
||||||
|
#cgo CFLAGS: -fno-stack-check
|
||||||
|
#cgo CFLAGS: -fno-stack-protector
|
||||||
|
#cgo CFLAGS: -mno-stack-arg-probe
|
||||||
|
#cgo LDFLAGS: -lmingwex -lmingw32
|
||||||
|
#cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T
|
||||||
|
*/
|
||||||
|
import "C"
|
672
vendor/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
Normal file
672
vendor/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
Normal file
|
@ -0,0 +1,672 @@
|
||||||
|
#ifndef USE_LIBSQLITE3
|
||||||
|
/*
|
||||||
|
** 2006 June 7
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
** This header file defines the SQLite interface for use by
|
||||||
|
** shared libraries that want to be imported as extensions into
|
||||||
|
** an SQLite instance. Shared libraries that intend to be loaded
|
||||||
|
** as extensions by SQLite should #include this file instead of
|
||||||
|
** sqlite3.h.
|
||||||
|
*/
|
||||||
|
#ifndef SQLITE3EXT_H
|
||||||
|
#define SQLITE3EXT_H
|
||||||
|
#include "sqlite3-binding.h"
|
||||||
|
#ifdef __clang__
|
||||||
|
#define assert(condition) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following structure holds pointers to all of the SQLite API
|
||||||
|
** routines.
|
||||||
|
**
|
||||||
|
** WARNING: In order to maintain backwards compatibility, add new
|
||||||
|
** interfaces to the end of this structure only. If you insert new
|
||||||
|
** interfaces in the middle of this structure, then older different
|
||||||
|
** versions of SQLite will not be able to load each other's shared
|
||||||
|
** libraries!
|
||||||
|
*/
|
||||||
|
struct sqlite3_api_routines {
|
||||||
|
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||||
|
int (*aggregate_count)(sqlite3_context*);
|
||||||
|
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||||
|
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||||
|
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||||
|
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||||
|
int (*bind_null)(sqlite3_stmt*,int);
|
||||||
|
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||||
|
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||||
|
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||||
|
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||||
|
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||||
|
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||||
|
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||||
|
int (*busy_timeout)(sqlite3*,int ms);
|
||||||
|
int (*changes)(sqlite3*);
|
||||||
|
int (*close)(sqlite3*);
|
||||||
|
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||||
|
int eTextRep,const char*));
|
||||||
|
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||||
|
int eTextRep,const void*));
|
||||||
|
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_count)(sqlite3_stmt*pStmt);
|
||||||
|
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||||
|
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||||
|
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||||
|
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||||
|
const char * (*column_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||||
|
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||||
|
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||||
|
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||||
|
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||||
|
int (*complete)(const char*sql);
|
||||||
|
int (*complete16)(const void*sql);
|
||||||
|
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||||
|
int(*)(void*,int,const void*,int,const void*));
|
||||||
|
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||||
|
int(*)(void*,int,const void*,int,const void*));
|
||||||
|
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||||
|
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*));
|
||||||
|
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||||
|
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*));
|
||||||
|
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||||
|
int (*data_count)(sqlite3_stmt*pStmt);
|
||||||
|
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||||
|
int (*declare_vtab)(sqlite3*,const char*);
|
||||||
|
int (*enable_shared_cache)(int);
|
||||||
|
int (*errcode)(sqlite3*db);
|
||||||
|
const char * (*errmsg)(sqlite3*);
|
||||||
|
const void * (*errmsg16)(sqlite3*);
|
||||||
|
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||||
|
int (*expired)(sqlite3_stmt*);
|
||||||
|
int (*finalize)(sqlite3_stmt*pStmt);
|
||||||
|
void (*free)(void*);
|
||||||
|
void (*free_table)(char**result);
|
||||||
|
int (*get_autocommit)(sqlite3*);
|
||||||
|
void * (*get_auxdata)(sqlite3_context*,int);
|
||||||
|
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||||
|
int (*global_recover)(void);
|
||||||
|
void (*interruptx)(sqlite3*);
|
||||||
|
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||||
|
const char * (*libversion)(void);
|
||||||
|
int (*libversion_number)(void);
|
||||||
|
void *(*malloc)(int);
|
||||||
|
char * (*mprintf)(const char*,...);
|
||||||
|
int (*open)(const char*,sqlite3**);
|
||||||
|
int (*open16)(const void*,sqlite3**);
|
||||||
|
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||||
|
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||||
|
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||||
|
void *(*realloc)(void*,int);
|
||||||
|
int (*reset)(sqlite3_stmt*pStmt);
|
||||||
|
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_double)(sqlite3_context*,double);
|
||||||
|
void (*result_error)(sqlite3_context*,const char*,int);
|
||||||
|
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||||
|
void (*result_int)(sqlite3_context*,int);
|
||||||
|
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||||
|
void (*result_null)(sqlite3_context*);
|
||||||
|
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||||
|
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||||
|
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||||
|
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||||
|
const char*,const char*),void*);
|
||||||
|
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||||
|
char * (*xsnprintf)(int,char*,const char*,...);
|
||||||
|
int (*step)(sqlite3_stmt*);
|
||||||
|
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||||
|
char const**,char const**,int*,int*,int*);
|
||||||
|
void (*thread_cleanup)(void);
|
||||||
|
int (*total_changes)(sqlite3*);
|
||||||
|
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||||
|
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||||
|
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||||
|
sqlite_int64),void*);
|
||||||
|
void * (*user_data)(sqlite3_context*);
|
||||||
|
const void * (*value_blob)(sqlite3_value*);
|
||||||
|
int (*value_bytes)(sqlite3_value*);
|
||||||
|
int (*value_bytes16)(sqlite3_value*);
|
||||||
|
double (*value_double)(sqlite3_value*);
|
||||||
|
int (*value_int)(sqlite3_value*);
|
||||||
|
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||||
|
int (*value_numeric_type)(sqlite3_value*);
|
||||||
|
const unsigned char * (*value_text)(sqlite3_value*);
|
||||||
|
const void * (*value_text16)(sqlite3_value*);
|
||||||
|
const void * (*value_text16be)(sqlite3_value*);
|
||||||
|
const void * (*value_text16le)(sqlite3_value*);
|
||||||
|
int (*value_type)(sqlite3_value*);
|
||||||
|
char *(*vmprintf)(const char*,va_list);
|
||||||
|
/* Added ??? */
|
||||||
|
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||||
|
/* Added by 3.3.13 */
|
||||||
|
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||||
|
int (*clear_bindings)(sqlite3_stmt*);
|
||||||
|
/* Added by 3.4.1 */
|
||||||
|
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||||
|
void (*xDestroy)(void *));
|
||||||
|
/* Added by 3.5.0 */
|
||||||
|
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||||
|
int (*blob_bytes)(sqlite3_blob*);
|
||||||
|
int (*blob_close)(sqlite3_blob*);
|
||||||
|
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||||
|
int,sqlite3_blob**);
|
||||||
|
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||||
|
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||||
|
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||||
|
int(*)(void*,int,const void*,int,const void*),
|
||||||
|
void(*)(void*));
|
||||||
|
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||||
|
sqlite3_int64 (*memory_highwater)(int);
|
||||||
|
sqlite3_int64 (*memory_used)(void);
|
||||||
|
sqlite3_mutex *(*mutex_alloc)(int);
|
||||||
|
void (*mutex_enter)(sqlite3_mutex*);
|
||||||
|
void (*mutex_free)(sqlite3_mutex*);
|
||||||
|
void (*mutex_leave)(sqlite3_mutex*);
|
||||||
|
int (*mutex_try)(sqlite3_mutex*);
|
||||||
|
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||||
|
int (*release_memory)(int);
|
||||||
|
void (*result_error_nomem)(sqlite3_context*);
|
||||||
|
void (*result_error_toobig)(sqlite3_context*);
|
||||||
|
int (*sleep)(int);
|
||||||
|
void (*soft_heap_limit)(int);
|
||||||
|
sqlite3_vfs *(*vfs_find)(const char*);
|
||||||
|
int (*vfs_register)(sqlite3_vfs*,int);
|
||||||
|
int (*vfs_unregister)(sqlite3_vfs*);
|
||||||
|
int (*xthreadsafe)(void);
|
||||||
|
void (*result_zeroblob)(sqlite3_context*,int);
|
||||||
|
void (*result_error_code)(sqlite3_context*,int);
|
||||||
|
int (*test_control)(int, ...);
|
||||||
|
void (*randomness)(int,void*);
|
||||||
|
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||||
|
int (*extended_result_codes)(sqlite3*,int);
|
||||||
|
int (*limit)(sqlite3*,int,int);
|
||||||
|
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||||
|
const char *(*sql)(sqlite3_stmt*);
|
||||||
|
int (*status)(int,int*,int*,int);
|
||||||
|
int (*backup_finish)(sqlite3_backup*);
|
||||||
|
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||||
|
int (*backup_pagecount)(sqlite3_backup*);
|
||||||
|
int (*backup_remaining)(sqlite3_backup*);
|
||||||
|
int (*backup_step)(sqlite3_backup*,int);
|
||||||
|
const char *(*compileoption_get)(int);
|
||||||
|
int (*compileoption_used)(const char*);
|
||||||
|
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||||
|
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*),
|
||||||
|
void(*xDestroy)(void*));
|
||||||
|
int (*db_config)(sqlite3*,int,...);
|
||||||
|
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||||
|
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||||
|
int (*extended_errcode)(sqlite3*);
|
||||||
|
void (*log)(int,const char*,...);
|
||||||
|
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||||
|
const char *(*sourceid)(void);
|
||||||
|
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||||
|
int (*strnicmp)(const char*,const char*,int);
|
||||||
|
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||||
|
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||||
|
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||||
|
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||||
|
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||||
|
int (*vtab_config)(sqlite3*,int op,...);
|
||||||
|
int (*vtab_on_conflict)(sqlite3*);
|
||||||
|
/* Version 3.7.16 and later */
|
||||||
|
int (*close_v2)(sqlite3*);
|
||||||
|
const char *(*db_filename)(sqlite3*,const char*);
|
||||||
|
int (*db_readonly)(sqlite3*,const char*);
|
||||||
|
int (*db_release_memory)(sqlite3*);
|
||||||
|
const char *(*errstr)(int);
|
||||||
|
int (*stmt_busy)(sqlite3_stmt*);
|
||||||
|
int (*stmt_readonly)(sqlite3_stmt*);
|
||||||
|
int (*stricmp)(const char*,const char*);
|
||||||
|
int (*uri_boolean)(const char*,const char*,int);
|
||||||
|
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||||
|
const char *(*uri_parameter)(const char*,const char*);
|
||||||
|
char *(*xvsnprintf)(int,char*,const char*,va_list);
|
||||||
|
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||||
|
/* Version 3.8.7 and later */
|
||||||
|
int (*auto_extension)(void(*)(void));
|
||||||
|
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||||
|
void(*)(void*));
|
||||||
|
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||||
|
void(*)(void*),unsigned char);
|
||||||
|
int (*cancel_auto_extension)(void(*)(void));
|
||||||
|
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||||
|
void *(*malloc64)(sqlite3_uint64);
|
||||||
|
sqlite3_uint64 (*msize)(void*);
|
||||||
|
void *(*realloc64)(void*,sqlite3_uint64);
|
||||||
|
void (*reset_auto_extension)(void);
|
||||||
|
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||||
|
void(*)(void*));
|
||||||
|
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||||
|
void(*)(void*), unsigned char);
|
||||||
|
int (*strglob)(const char*,const char*);
|
||||||
|
/* Version 3.8.11 and later */
|
||||||
|
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||||
|
void (*value_free)(sqlite3_value*);
|
||||||
|
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||||
|
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||||
|
/* Version 3.9.0 and later */
|
||||||
|
unsigned int (*value_subtype)(sqlite3_value*);
|
||||||
|
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||||
|
/* Version 3.10.0 and later */
|
||||||
|
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||||
|
int (*strlike)(const char*,const char*,unsigned int);
|
||||||
|
int (*db_cacheflush)(sqlite3*);
|
||||||
|
/* Version 3.12.0 and later */
|
||||||
|
int (*system_errno)(sqlite3*);
|
||||||
|
/* Version 3.14.0 and later */
|
||||||
|
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||||
|
char *(*expanded_sql)(sqlite3_stmt*);
|
||||||
|
/* Version 3.18.0 and later */
|
||||||
|
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||||
|
/* Version 3.20.0 and later */
|
||||||
|
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
|
||||||
|
sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
|
||||||
|
sqlite3_stmt**,const void**);
|
||||||
|
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||||
|
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||||
|
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||||
|
int (*vtab_nochange)(sqlite3_context*);
|
||||||
|
int (*value_nochange)(sqlite3_value*);
|
||||||
|
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||||
|
/* Version 3.24.0 and later */
|
||||||
|
int (*keyword_count)(void);
|
||||||
|
int (*keyword_name)(int,const char**,int*);
|
||||||
|
int (*keyword_check)(const char*,int);
|
||||||
|
sqlite3_str *(*str_new)(sqlite3*);
|
||||||
|
char *(*str_finish)(sqlite3_str*);
|
||||||
|
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
|
||||||
|
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
|
||||||
|
void (*str_append)(sqlite3_str*, const char *zIn, int N);
|
||||||
|
void (*str_appendall)(sqlite3_str*, const char *zIn);
|
||||||
|
void (*str_appendchar)(sqlite3_str*, int N, char C);
|
||||||
|
void (*str_reset)(sqlite3_str*);
|
||||||
|
int (*str_errcode)(sqlite3_str*);
|
||||||
|
int (*str_length)(sqlite3_str*);
|
||||||
|
char *(*str_value)(sqlite3_str*);
|
||||||
|
/* Version 3.25.0 and later */
|
||||||
|
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*),
|
||||||
|
void (*xValue)(sqlite3_context*),
|
||||||
|
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void(*xDestroy)(void*));
|
||||||
|
/* Version 3.26.0 and later */
|
||||||
|
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||||
|
/* Version 3.28.0 and later */
|
||||||
|
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||||
|
int (*value_frombind)(sqlite3_value*);
|
||||||
|
/* Version 3.30.0 and later */
|
||||||
|
int (*drop_modules)(sqlite3*,const char**);
|
||||||
|
/* Version 3.31.0 and later */
|
||||||
|
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
|
||||||
|
const char *(*uri_key)(const char*,int);
|
||||||
|
const char *(*filename_database)(const char*);
|
||||||
|
const char *(*filename_journal)(const char*);
|
||||||
|
const char *(*filename_wal)(const char*);
|
||||||
|
/* Version 3.32.0 and later */
|
||||||
|
char *(*create_filename)(const char*,const char*,const char*,
|
||||||
|
int,const char**);
|
||||||
|
void (*free_filename)(char*);
|
||||||
|
sqlite3_file *(*database_file_object)(const char*);
|
||||||
|
/* Version 3.34.0 and later */
|
||||||
|
int (*txn_state)(sqlite3*,const char*);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This is the function signature used for all extension entry points. It
|
||||||
|
** is also defined in the file "loadext.c".
|
||||||
|
*/
|
||||||
|
typedef int (*sqlite3_loadext_entry)(
|
||||||
|
sqlite3 *db, /* Handle to the database. */
|
||||||
|
char **pzErrMsg, /* Used to set error string on failure. */
|
||||||
|
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following macros redefine the API routines so that they are
|
||||||
|
** redirected through the global sqlite3_api structure.
|
||||||
|
**
|
||||||
|
** This header file is also used by the loadext.c source file
|
||||||
|
** (part of the main SQLite library - not an extension) so that
|
||||||
|
** it can get access to the sqlite3_api_routines structure
|
||||||
|
** definition. But the main library does not want to redefine
|
||||||
|
** the API. So the redefinition macros are only valid if the
|
||||||
|
** SQLITE_CORE macros is undefined.
|
||||||
|
*/
|
||||||
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||||
|
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||||
|
#endif
|
||||||
|
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||||
|
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||||
|
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||||
|
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||||
|
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||||
|
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||||
|
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||||
|
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||||
|
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||||
|
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||||
|
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||||
|
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||||
|
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||||
|
#define sqlite3_changes sqlite3_api->changes
|
||||||
|
#define sqlite3_close sqlite3_api->close
|
||||||
|
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||||
|
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||||
|
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||||
|
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||||
|
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||||
|
#define sqlite3_column_count sqlite3_api->column_count
|
||||||
|
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||||
|
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||||
|
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||||
|
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||||
|
#define sqlite3_column_double sqlite3_api->column_double
|
||||||
|
#define sqlite3_column_int sqlite3_api->column_int
|
||||||
|
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||||
|
#define sqlite3_column_name sqlite3_api->column_name
|
||||||
|
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||||
|
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||||
|
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||||
|
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||||
|
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||||
|
#define sqlite3_column_text sqlite3_api->column_text
|
||||||
|
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||||
|
#define sqlite3_column_type sqlite3_api->column_type
|
||||||
|
#define sqlite3_column_value sqlite3_api->column_value
|
||||||
|
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||||
|
#define sqlite3_complete sqlite3_api->complete
|
||||||
|
#define sqlite3_complete16 sqlite3_api->complete16
|
||||||
|
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||||
|
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||||
|
#define sqlite3_create_function sqlite3_api->create_function
|
||||||
|
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||||
|
#define sqlite3_create_module sqlite3_api->create_module
|
||||||
|
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||||
|
#define sqlite3_data_count sqlite3_api->data_count
|
||||||
|
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||||
|
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||||
|
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||||
|
#define sqlite3_errcode sqlite3_api->errcode
|
||||||
|
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||||
|
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||||
|
#define sqlite3_exec sqlite3_api->exec
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_expired sqlite3_api->expired
|
||||||
|
#endif
|
||||||
|
#define sqlite3_finalize sqlite3_api->finalize
|
||||||
|
#define sqlite3_free sqlite3_api->free
|
||||||
|
#define sqlite3_free_table sqlite3_api->free_table
|
||||||
|
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||||
|
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||||
|
#define sqlite3_get_table sqlite3_api->get_table
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||||
|
#endif
|
||||||
|
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||||
|
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||||
|
#define sqlite3_libversion sqlite3_api->libversion
|
||||||
|
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||||
|
#define sqlite3_malloc sqlite3_api->malloc
|
||||||
|
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||||
|
#define sqlite3_open sqlite3_api->open
|
||||||
|
#define sqlite3_open16 sqlite3_api->open16
|
||||||
|
#define sqlite3_prepare sqlite3_api->prepare
|
||||||
|
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||||
|
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||||
|
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||||
|
#define sqlite3_profile sqlite3_api->profile
|
||||||
|
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||||
|
#define sqlite3_realloc sqlite3_api->realloc
|
||||||
|
#define sqlite3_reset sqlite3_api->reset
|
||||||
|
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||||
|
#define sqlite3_result_double sqlite3_api->result_double
|
||||||
|
#define sqlite3_result_error sqlite3_api->result_error
|
||||||
|
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||||
|
#define sqlite3_result_int sqlite3_api->result_int
|
||||||
|
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||||
|
#define sqlite3_result_null sqlite3_api->result_null
|
||||||
|
#define sqlite3_result_text sqlite3_api->result_text
|
||||||
|
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||||
|
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||||
|
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||||
|
#define sqlite3_result_value sqlite3_api->result_value
|
||||||
|
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||||
|
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||||
|
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||||
|
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||||
|
#define sqlite3_step sqlite3_api->step
|
||||||
|
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||||
|
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||||
|
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||||
|
#define sqlite3_trace sqlite3_api->trace
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||||
|
#endif
|
||||||
|
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||||
|
#define sqlite3_user_data sqlite3_api->user_data
|
||||||
|
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||||
|
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||||
|
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||||
|
#define sqlite3_value_double sqlite3_api->value_double
|
||||||
|
#define sqlite3_value_int sqlite3_api->value_int
|
||||||
|
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||||
|
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||||
|
#define sqlite3_value_text sqlite3_api->value_text
|
||||||
|
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||||
|
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||||
|
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||||
|
#define sqlite3_value_type sqlite3_api->value_type
|
||||||
|
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||||
|
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
|
||||||
|
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||||
|
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||||
|
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||||
|
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||||
|
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||||
|
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||||
|
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||||
|
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||||
|
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||||
|
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||||
|
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||||
|
#define sqlite3_file_control sqlite3_api->file_control
|
||||||
|
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||||
|
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||||
|
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||||
|
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||||
|
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||||
|
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||||
|
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||||
|
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||||
|
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||||
|
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||||
|
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||||
|
#define sqlite3_sleep sqlite3_api->sleep
|
||||||
|
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||||
|
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||||
|
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||||
|
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||||
|
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||||
|
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||||
|
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||||
|
#define sqlite3_test_control sqlite3_api->test_control
|
||||||
|
#define sqlite3_randomness sqlite3_api->randomness
|
||||||
|
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||||
|
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||||
|
#define sqlite3_limit sqlite3_api->limit
|
||||||
|
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||||
|
#define sqlite3_sql sqlite3_api->sql
|
||||||
|
#define sqlite3_status sqlite3_api->status
|
||||||
|
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||||
|
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||||
|
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||||
|
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||||
|
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||||
|
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||||
|
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||||
|
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||||
|
#define sqlite3_db_config sqlite3_api->db_config
|
||||||
|
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||||
|
#define sqlite3_db_status sqlite3_api->db_status
|
||||||
|
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||||
|
#define sqlite3_log sqlite3_api->log
|
||||||
|
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||||
|
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||||
|
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||||
|
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||||
|
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||||
|
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||||
|
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||||
|
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||||
|
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||||
|
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||||
|
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||||
|
/* Version 3.7.16 and later */
|
||||||
|
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||||
|
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||||
|
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||||
|
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||||
|
#define sqlite3_errstr sqlite3_api->errstr
|
||||||
|
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||||
|
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||||
|
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||||
|
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||||
|
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||||
|
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||||
|
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
|
||||||
|
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||||
|
/* Version 3.8.7 and later */
|
||||||
|
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||||
|
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||||
|
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||||
|
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||||
|
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||||
|
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||||
|
#define sqlite3_msize sqlite3_api->msize
|
||||||
|
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||||
|
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||||
|
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||||
|
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||||
|
#define sqlite3_strglob sqlite3_api->strglob
|
||||||
|
/* Version 3.8.11 and later */
|
||||||
|
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||||
|
#define sqlite3_value_free sqlite3_api->value_free
|
||||||
|
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||||
|
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||||
|
/* Version 3.9.0 and later */
|
||||||
|
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||||
|
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||||
|
/* Version 3.10.0 and later */
|
||||||
|
#define sqlite3_status64 sqlite3_api->status64
|
||||||
|
#define sqlite3_strlike sqlite3_api->strlike
|
||||||
|
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||||
|
/* Version 3.12.0 and later */
|
||||||
|
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||||
|
/* Version 3.14.0 and later */
|
||||||
|
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||||
|
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||||
|
/* Version 3.18.0 and later */
|
||||||
|
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||||
|
/* Version 3.20.0 and later */
|
||||||
|
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
|
||||||
|
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
|
||||||
|
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||||
|
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||||
|
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||||
|
/* Version 3.22.0 and later */
|
||||||
|
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||||
|
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||||
|
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||||
|
/* Version 3.24.0 and later */
|
||||||
|
#define sqlite3_keyword_count sqlite3_api->keyword_count
|
||||||
|
#define sqlite3_keyword_name sqlite3_api->keyword_name
|
||||||
|
#define sqlite3_keyword_check sqlite3_api->keyword_check
|
||||||
|
#define sqlite3_str_new sqlite3_api->str_new
|
||||||
|
#define sqlite3_str_finish sqlite3_api->str_finish
|
||||||
|
#define sqlite3_str_appendf sqlite3_api->str_appendf
|
||||||
|
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
|
||||||
|
#define sqlite3_str_append sqlite3_api->str_append
|
||||||
|
#define sqlite3_str_appendall sqlite3_api->str_appendall
|
||||||
|
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
|
||||||
|
#define sqlite3_str_reset sqlite3_api->str_reset
|
||||||
|
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||||
|
#define sqlite3_str_length sqlite3_api->str_length
|
||||||
|
#define sqlite3_str_value sqlite3_api->str_value
|
||||||
|
/* Version 3.25.0 and later */
|
||||||
|
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||||
|
/* Version 3.26.0 and later */
|
||||||
|
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||||
|
/* Version 3.28.0 and later */
|
||||||
|
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
|
||||||
|
#define sqlite3_value_frombind sqlite3_api->value_frombind
|
||||||
|
/* Version 3.30.0 and later */
|
||||||
|
#define sqlite3_drop_modules sqlite3_api->drop_modules
|
||||||
|
/* Version 3.31.0 and later */
|
||||||
|
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
|
||||||
|
#define sqlite3_uri_key sqlite3_api->uri_key
|
||||||
|
#define sqlite3_filename_database sqlite3_api->filename_database
|
||||||
|
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
||||||
|
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
||||||
|
/* Version 3.32.0 and later */
|
||||||
|
#define sqlite3_create_filename sqlite3_api->create_filename
|
||||||
|
#define sqlite3_free_filename sqlite3_api->free_filename
|
||||||
|
#define sqlite3_database_file_object sqlite3_api->database_file_object
|
||||||
|
/* Version 3.34.0 and later */
|
||||||
|
#define sqlite3_txn_state sqlite3_api->txn_state
|
||||||
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||||
|
|
||||||
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||||
|
/* This case when the file really is being compiled as a loadable
|
||||||
|
** extension */
|
||||||
|
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||||
|
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||||
|
# define SQLITE_EXTENSION_INIT3 \
|
||||||
|
extern const sqlite3_api_routines *sqlite3_api;
|
||||||
|
#else
|
||||||
|
/* This case when the file is being statically linked into the
|
||||||
|
** application */
|
||||||
|
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||||
|
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||||
|
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SQLITE3EXT_H */
|
||||||
|
#else // USE_LIBSQLITE3
|
||||||
|
// If users really want to link against the system sqlite3 we
|
||||||
|
// need to make this file a noop.
|
||||||
|
#endif
|
37
vendor/github.com/mattn/go-sqlite3/static_mock.go
generated
vendored
Normal file
37
vendor/github.com/mattn/go-sqlite3/static_mock.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !cgo
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errorMsg = errors.New("Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub")
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
sql.Register("sqlite3", &SQLiteDriver{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
SQLiteDriver struct {
|
||||||
|
Extensions []string
|
||||||
|
ConnectHook func(*SQLiteConn) error
|
||||||
|
}
|
||||||
|
SQLiteConn struct{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (SQLiteDriver) Open(s string) (driver.Conn, error) { return nil, errorMsg }
|
||||||
|
func (c *SQLiteConn) RegisterAggregator(string, interface{}, bool) error { return errorMsg }
|
||||||
|
func (c *SQLiteConn) RegisterAuthorizer(func(int, string, string, string) int) {}
|
||||||
|
func (c *SQLiteConn) RegisterCollation(string, func(string, string) int) error { return errorMsg }
|
||||||
|
func (c *SQLiteConn) RegisterCommitHook(func() int) {}
|
||||||
|
func (c *SQLiteConn) RegisterFunc(string, interface{}, bool) error { return errorMsg }
|
||||||
|
func (c *SQLiteConn) RegisterRollbackHook(func()) {}
|
||||||
|
func (c *SQLiteConn) RegisterUpdateHook(func(int, string, string, int64)) {}
|
27
vendor/github.com/pmezard/go-difflib/LICENSE
generated
vendored
Normal file
27
vendor/github.com/pmezard/go-difflib/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2013, Patrick Mezard
|
||||||
|
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.
|
||||||
|
The names of its contributors may not 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
|
||||||
|
HOLDER 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.
|
772
vendor/github.com/pmezard/go-difflib/difflib/difflib.go
generated
vendored
Normal file
772
vendor/github.com/pmezard/go-difflib/difflib/difflib.go
generated
vendored
Normal file
|
@ -0,0 +1,772 @@
|
||||||
|
// Package difflib is a partial port of Python difflib module.
|
||||||
|
//
|
||||||
|
// It provides tools to compare sequences of strings and generate textual diffs.
|
||||||
|
//
|
||||||
|
// The following class and functions have been ported:
|
||||||
|
//
|
||||||
|
// - SequenceMatcher
|
||||||
|
//
|
||||||
|
// - unified_diff
|
||||||
|
//
|
||||||
|
// - context_diff
|
||||||
|
//
|
||||||
|
// Getting unified diffs was the main goal of the port. Keep in mind this code
|
||||||
|
// is mostly suitable to output text differences in a human friendly way, there
|
||||||
|
// are no guarantees generated diffs are consumable by patch(1).
|
||||||
|
package difflib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateRatio(matches, length int) float64 {
|
||||||
|
if length > 0 {
|
||||||
|
return 2.0 * float64(matches) / float64(length)
|
||||||
|
}
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
A int
|
||||||
|
B int
|
||||||
|
Size int
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpCode struct {
|
||||||
|
Tag byte
|
||||||
|
I1 int
|
||||||
|
I2 int
|
||||||
|
J1 int
|
||||||
|
J2 int
|
||||||
|
}
|
||||||
|
|
||||||
|
// SequenceMatcher compares sequence of strings. The basic
|
||||||
|
// algorithm predates, and is a little fancier than, an algorithm
|
||||||
|
// published in the late 1980's by Ratcliff and Obershelp under the
|
||||||
|
// hyperbolic name "gestalt pattern matching". The basic idea is to find
|
||||||
|
// the longest contiguous matching subsequence that contains no "junk"
|
||||||
|
// elements (R-O doesn't address junk). The same idea is then applied
|
||||||
|
// recursively to the pieces of the sequences to the left and to the right
|
||||||
|
// of the matching subsequence. This does not yield minimal edit
|
||||||
|
// sequences, but does tend to yield matches that "look right" to people.
|
||||||
|
//
|
||||||
|
// SequenceMatcher tries to compute a "human-friendly diff" between two
|
||||||
|
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
|
||||||
|
// longest *contiguous* & junk-free matching subsequence. That's what
|
||||||
|
// catches peoples' eyes. The Windows(tm) windiff has another interesting
|
||||||
|
// notion, pairing up elements that appear uniquely in each sequence.
|
||||||
|
// That, and the method here, appear to yield more intuitive difference
|
||||||
|
// reports than does diff. This method appears to be the least vulnerable
|
||||||
|
// to synching up on blocks of "junk lines", though (like blank lines in
|
||||||
|
// ordinary text files, or maybe "<P>" lines in HTML files). That may be
|
||||||
|
// because this is the only method of the 3 that has a *concept* of
|
||||||
|
// "junk" <wink>.
|
||||||
|
//
|
||||||
|
// Timing: Basic R-O is cubic time worst case and quadratic time expected
|
||||||
|
// case. SequenceMatcher is quadratic time for the worst case and has
|
||||||
|
// expected-case behavior dependent in a complicated way on how many
|
||||||
|
// elements the sequences have in common; best case time is linear.
|
||||||
|
type SequenceMatcher struct {
|
||||||
|
a []string
|
||||||
|
b []string
|
||||||
|
b2j map[string][]int
|
||||||
|
IsJunk func(string) bool
|
||||||
|
autoJunk bool
|
||||||
|
bJunk map[string]struct{}
|
||||||
|
matchingBlocks []Match
|
||||||
|
fullBCount map[string]int
|
||||||
|
bPopular map[string]struct{}
|
||||||
|
opCodes []OpCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMatcher(a, b []string) *SequenceMatcher {
|
||||||
|
m := SequenceMatcher{autoJunk: true}
|
||||||
|
m.SetSeqs(a, b)
|
||||||
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMatcherWithJunk(a, b []string, autoJunk bool,
|
||||||
|
isJunk func(string) bool) *SequenceMatcher {
|
||||||
|
|
||||||
|
m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
|
||||||
|
m.SetSeqs(a, b)
|
||||||
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set two sequences to be compared.
|
||||||
|
func (m *SequenceMatcher) SetSeqs(a, b []string) {
|
||||||
|
m.SetSeq1(a)
|
||||||
|
m.SetSeq2(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the first sequence to be compared. The second sequence to be compared is
|
||||||
|
// not changed.
|
||||||
|
//
|
||||||
|
// SequenceMatcher computes and caches detailed information about the second
|
||||||
|
// sequence, so if you want to compare one sequence S against many sequences,
|
||||||
|
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
|
||||||
|
// sequences.
|
||||||
|
//
|
||||||
|
// See also SetSeqs() and SetSeq2().
|
||||||
|
func (m *SequenceMatcher) SetSeq1(a []string) {
|
||||||
|
if &a == &m.a {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.a = a
|
||||||
|
m.matchingBlocks = nil
|
||||||
|
m.opCodes = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the second sequence to be compared. The first sequence to be compared is
|
||||||
|
// not changed.
|
||||||
|
func (m *SequenceMatcher) SetSeq2(b []string) {
|
||||||
|
if &b == &m.b {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.b = b
|
||||||
|
m.matchingBlocks = nil
|
||||||
|
m.opCodes = nil
|
||||||
|
m.fullBCount = nil
|
||||||
|
m.chainB()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SequenceMatcher) chainB() {
|
||||||
|
// Populate line -> index mapping
|
||||||
|
b2j := map[string][]int{}
|
||||||
|
for i, s := range m.b {
|
||||||
|
indices := b2j[s]
|
||||||
|
indices = append(indices, i)
|
||||||
|
b2j[s] = indices
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge junk elements
|
||||||
|
m.bJunk = map[string]struct{}{}
|
||||||
|
if m.IsJunk != nil {
|
||||||
|
junk := m.bJunk
|
||||||
|
for s, _ := range b2j {
|
||||||
|
if m.IsJunk(s) {
|
||||||
|
junk[s] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for s, _ := range junk {
|
||||||
|
delete(b2j, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge remaining popular elements
|
||||||
|
popular := map[string]struct{}{}
|
||||||
|
n := len(m.b)
|
||||||
|
if m.autoJunk && n >= 200 {
|
||||||
|
ntest := n/100 + 1
|
||||||
|
for s, indices := range b2j {
|
||||||
|
if len(indices) > ntest {
|
||||||
|
popular[s] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for s, _ := range popular {
|
||||||
|
delete(b2j, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.bPopular = popular
|
||||||
|
m.b2j = b2j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SequenceMatcher) isBJunk(s string) bool {
|
||||||
|
_, ok := m.bJunk[s]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
|
||||||
|
//
|
||||||
|
// If IsJunk is not defined:
|
||||||
|
//
|
||||||
|
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
|
||||||
|
// alo <= i <= i+k <= ahi
|
||||||
|
// blo <= j <= j+k <= bhi
|
||||||
|
// and for all (i',j',k') meeting those conditions,
|
||||||
|
// k >= k'
|
||||||
|
// i <= i'
|
||||||
|
// and if i == i', j <= j'
|
||||||
|
//
|
||||||
|
// In other words, of all maximal matching blocks, return one that
|
||||||
|
// starts earliest in a, and of all those maximal matching blocks that
|
||||||
|
// start earliest in a, return the one that starts earliest in b.
|
||||||
|
//
|
||||||
|
// If IsJunk is defined, first the longest matching block is
|
||||||
|
// determined as above, but with the additional restriction that no
|
||||||
|
// junk element appears in the block. Then that block is extended as
|
||||||
|
// far as possible by matching (only) junk elements on both sides. So
|
||||||
|
// the resulting block never matches on junk except as identical junk
|
||||||
|
// happens to be adjacent to an "interesting" match.
|
||||||
|
//
|
||||||
|
// If no blocks match, return (alo, blo, 0).
|
||||||
|
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
|
||||||
|
// CAUTION: stripping common prefix or suffix would be incorrect.
|
||||||
|
// E.g.,
|
||||||
|
// ab
|
||||||
|
// acab
|
||||||
|
// Longest matching block is "ab", but if common prefix is
|
||||||
|
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
|
||||||
|
// strip, so ends up claiming that ab is changed to acab by
|
||||||
|
// inserting "ca" in the middle. That's minimal but unintuitive:
|
||||||
|
// "it's obvious" that someone inserted "ac" at the front.
|
||||||
|
// Windiff ends up at the same place as diff, but by pairing up
|
||||||
|
// the unique 'b's and then matching the first two 'a's.
|
||||||
|
besti, bestj, bestsize := alo, blo, 0
|
||||||
|
|
||||||
|
// find longest junk-free match
|
||||||
|
// during an iteration of the loop, j2len[j] = length of longest
|
||||||
|
// junk-free match ending with a[i-1] and b[j]
|
||||||
|
j2len := map[int]int{}
|
||||||
|
for i := alo; i != ahi; i++ {
|
||||||
|
// look at all instances of a[i] in b; note that because
|
||||||
|
// b2j has no junk keys, the loop is skipped if a[i] is junk
|
||||||
|
newj2len := map[int]int{}
|
||||||
|
for _, j := range m.b2j[m.a[i]] {
|
||||||
|
// a[i] matches b[j]
|
||||||
|
if j < blo {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if j >= bhi {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
k := j2len[j-1] + 1
|
||||||
|
newj2len[j] = k
|
||||||
|
if k > bestsize {
|
||||||
|
besti, bestj, bestsize = i-k+1, j-k+1, k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j2len = newj2len
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend the best by non-junk elements on each end. In particular,
|
||||||
|
// "popular" non-junk elements aren't in b2j, which greatly speeds
|
||||||
|
// the inner loop above, but also means "the best" match so far
|
||||||
|
// doesn't contain any junk *or* popular non-junk elements.
|
||||||
|
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
|
||||||
|
m.a[besti-1] == m.b[bestj-1] {
|
||||||
|
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
||||||
|
}
|
||||||
|
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
||||||
|
!m.isBJunk(m.b[bestj+bestsize]) &&
|
||||||
|
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
||||||
|
bestsize += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we have a wholly interesting match (albeit possibly
|
||||||
|
// empty!), we may as well suck up the matching junk on each
|
||||||
|
// side of it too. Can't think of a good reason not to, and it
|
||||||
|
// saves post-processing the (possibly considerable) expense of
|
||||||
|
// figuring out what to do with it. In the case of an empty
|
||||||
|
// interesting match, this is clearly the right thing to do,
|
||||||
|
// because no other kind of match is possible in the regions.
|
||||||
|
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
|
||||||
|
m.a[besti-1] == m.b[bestj-1] {
|
||||||
|
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
||||||
|
}
|
||||||
|
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
||||||
|
m.isBJunk(m.b[bestj+bestsize]) &&
|
||||||
|
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
||||||
|
bestsize += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return Match{A: besti, B: bestj, Size: bestsize}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return list of triples describing matching subsequences.
|
||||||
|
//
|
||||||
|
// Each triple is of the form (i, j, n), and means that
|
||||||
|
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
|
||||||
|
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
|
||||||
|
// adjacent triples in the list, and the second is not the last triple in the
|
||||||
|
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
|
||||||
|
// adjacent equal blocks.
|
||||||
|
//
|
||||||
|
// The last triple is a dummy, (len(a), len(b), 0), and is the only
|
||||||
|
// triple with n==0.
|
||||||
|
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
|
||||||
|
if m.matchingBlocks != nil {
|
||||||
|
return m.matchingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
|
||||||
|
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
|
||||||
|
match := m.findLongestMatch(alo, ahi, blo, bhi)
|
||||||
|
i, j, k := match.A, match.B, match.Size
|
||||||
|
if match.Size > 0 {
|
||||||
|
if alo < i && blo < j {
|
||||||
|
matched = matchBlocks(alo, i, blo, j, matched)
|
||||||
|
}
|
||||||
|
matched = append(matched, match)
|
||||||
|
if i+k < ahi && j+k < bhi {
|
||||||
|
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matched
|
||||||
|
}
|
||||||
|
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
|
||||||
|
|
||||||
|
// It's possible that we have adjacent equal blocks in the
|
||||||
|
// matching_blocks list now.
|
||||||
|
nonAdjacent := []Match{}
|
||||||
|
i1, j1, k1 := 0, 0, 0
|
||||||
|
for _, b := range matched {
|
||||||
|
// Is this block adjacent to i1, j1, k1?
|
||||||
|
i2, j2, k2 := b.A, b.B, b.Size
|
||||||
|
if i1+k1 == i2 && j1+k1 == j2 {
|
||||||
|
// Yes, so collapse them -- this just increases the length of
|
||||||
|
// the first block by the length of the second, and the first
|
||||||
|
// block so lengthened remains the block to compare against.
|
||||||
|
k1 += k2
|
||||||
|
} else {
|
||||||
|
// Not adjacent. Remember the first block (k1==0 means it's
|
||||||
|
// the dummy we started with), and make the second block the
|
||||||
|
// new block to compare against.
|
||||||
|
if k1 > 0 {
|
||||||
|
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
||||||
|
}
|
||||||
|
i1, j1, k1 = i2, j2, k2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k1 > 0 {
|
||||||
|
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
||||||
|
}
|
||||||
|
|
||||||
|
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
|
||||||
|
m.matchingBlocks = nonAdjacent
|
||||||
|
return m.matchingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return list of 5-tuples describing how to turn a into b.
|
||||||
|
//
|
||||||
|
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
|
||||||
|
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
|
||||||
|
// tuple preceding it, and likewise for j1 == the previous j2.
|
||||||
|
//
|
||||||
|
// The tags are characters, with these meanings:
|
||||||
|
//
|
||||||
|
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
|
||||||
|
//
|
||||||
|
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
|
||||||
|
//
|
||||||
|
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
|
||||||
|
//
|
||||||
|
// 'e' (equal): a[i1:i2] == b[j1:j2]
|
||||||
|
func (m *SequenceMatcher) GetOpCodes() []OpCode {
|
||||||
|
if m.opCodes != nil {
|
||||||
|
return m.opCodes
|
||||||
|
}
|
||||||
|
i, j := 0, 0
|
||||||
|
matching := m.GetMatchingBlocks()
|
||||||
|
opCodes := make([]OpCode, 0, len(matching))
|
||||||
|
for _, m := range matching {
|
||||||
|
// invariant: we've pumped out correct diffs to change
|
||||||
|
// a[:i] into b[:j], and the next matching block is
|
||||||
|
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
|
||||||
|
// out a diff to change a[i:ai] into b[j:bj], pump out
|
||||||
|
// the matching block, and move (i,j) beyond the match
|
||||||
|
ai, bj, size := m.A, m.B, m.Size
|
||||||
|
tag := byte(0)
|
||||||
|
if i < ai && j < bj {
|
||||||
|
tag = 'r'
|
||||||
|
} else if i < ai {
|
||||||
|
tag = 'd'
|
||||||
|
} else if j < bj {
|
||||||
|
tag = 'i'
|
||||||
|
}
|
||||||
|
if tag > 0 {
|
||||||
|
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
|
||||||
|
}
|
||||||
|
i, j = ai+size, bj+size
|
||||||
|
// the list of matching blocks is terminated by a
|
||||||
|
// sentinel with size 0
|
||||||
|
if size > 0 {
|
||||||
|
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.opCodes = opCodes
|
||||||
|
return m.opCodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Isolate change clusters by eliminating ranges with no changes.
|
||||||
|
//
|
||||||
|
// Return a generator of groups with up to n lines of context.
|
||||||
|
// Each group is in the same format as returned by GetOpCodes().
|
||||||
|
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
|
||||||
|
if n < 0 {
|
||||||
|
n = 3
|
||||||
|
}
|
||||||
|
codes := m.GetOpCodes()
|
||||||
|
if len(codes) == 0 {
|
||||||
|
codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
|
||||||
|
}
|
||||||
|
// Fixup leading and trailing groups if they show no changes.
|
||||||
|
if codes[0].Tag == 'e' {
|
||||||
|
c := codes[0]
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
|
||||||
|
}
|
||||||
|
if codes[len(codes)-1].Tag == 'e' {
|
||||||
|
c := codes[len(codes)-1]
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
|
||||||
|
}
|
||||||
|
nn := n + n
|
||||||
|
groups := [][]OpCode{}
|
||||||
|
group := []OpCode{}
|
||||||
|
for _, c := range codes {
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
// End the current group and start a new one whenever
|
||||||
|
// there is a large range with no changes.
|
||||||
|
if c.Tag == 'e' && i2-i1 > nn {
|
||||||
|
group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
|
||||||
|
j1, min(j2, j1+n)})
|
||||||
|
groups = append(groups, group)
|
||||||
|
group = []OpCode{}
|
||||||
|
i1, j1 = max(i1, i2-n), max(j1, j2-n)
|
||||||
|
}
|
||||||
|
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
|
||||||
|
}
|
||||||
|
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
|
||||||
|
groups = append(groups, group)
|
||||||
|
}
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a measure of the sequences' similarity (float in [0,1]).
|
||||||
|
//
|
||||||
|
// Where T is the total number of elements in both sequences, and
|
||||||
|
// M is the number of matches, this is 2.0*M / T.
|
||||||
|
// Note that this is 1 if the sequences are identical, and 0 if
|
||||||
|
// they have nothing in common.
|
||||||
|
//
|
||||||
|
// .Ratio() is expensive to compute if you haven't already computed
|
||||||
|
// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
|
||||||
|
// want to try .QuickRatio() or .RealQuickRation() first to get an
|
||||||
|
// upper bound.
|
||||||
|
func (m *SequenceMatcher) Ratio() float64 {
|
||||||
|
matches := 0
|
||||||
|
for _, m := range m.GetMatchingBlocks() {
|
||||||
|
matches += m.Size
|
||||||
|
}
|
||||||
|
return calculateRatio(matches, len(m.a)+len(m.b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an upper bound on ratio() relatively quickly.
|
||||||
|
//
|
||||||
|
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
||||||
|
// is faster to compute.
|
||||||
|
func (m *SequenceMatcher) QuickRatio() float64 {
|
||||||
|
// viewing a and b as multisets, set matches to the cardinality
|
||||||
|
// of their intersection; this counts the number of matches
|
||||||
|
// without regard to order, so is clearly an upper bound
|
||||||
|
if m.fullBCount == nil {
|
||||||
|
m.fullBCount = map[string]int{}
|
||||||
|
for _, s := range m.b {
|
||||||
|
m.fullBCount[s] = m.fullBCount[s] + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// avail[x] is the number of times x appears in 'b' less the
|
||||||
|
// number of times we've seen it in 'a' so far ... kinda
|
||||||
|
avail := map[string]int{}
|
||||||
|
matches := 0
|
||||||
|
for _, s := range m.a {
|
||||||
|
n, ok := avail[s]
|
||||||
|
if !ok {
|
||||||
|
n = m.fullBCount[s]
|
||||||
|
}
|
||||||
|
avail[s] = n - 1
|
||||||
|
if n > 0 {
|
||||||
|
matches += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return calculateRatio(matches, len(m.a)+len(m.b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an upper bound on ratio() very quickly.
|
||||||
|
//
|
||||||
|
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
||||||
|
// is faster to compute than either .Ratio() or .QuickRatio().
|
||||||
|
func (m *SequenceMatcher) RealQuickRatio() float64 {
|
||||||
|
la, lb := len(m.a), len(m.b)
|
||||||
|
return calculateRatio(min(la, lb), la+lb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert range to the "ed" format
|
||||||
|
func formatRangeUnified(start, stop int) string {
|
||||||
|
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
||||||
|
beginning := start + 1 // lines start numbering with one
|
||||||
|
length := stop - start
|
||||||
|
if length == 1 {
|
||||||
|
return fmt.Sprintf("%d", beginning)
|
||||||
|
}
|
||||||
|
if length == 0 {
|
||||||
|
beginning -= 1 // empty ranges begin at line just before the range
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d,%d", beginning, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unified diff parameters
|
||||||
|
type UnifiedDiff struct {
|
||||||
|
A []string // First sequence lines
|
||||||
|
FromFile string // First file name
|
||||||
|
FromDate string // First file time
|
||||||
|
B []string // Second sequence lines
|
||||||
|
ToFile string // Second file name
|
||||||
|
ToDate string // Second file time
|
||||||
|
Eol string // Headers end of line, defaults to LF
|
||||||
|
Context int // Number of context lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two sequences of lines; generate the delta as a unified diff.
|
||||||
|
//
|
||||||
|
// Unified diffs are a compact way of showing line changes and a few
|
||||||
|
// lines of context. The number of context lines is set by 'n' which
|
||||||
|
// defaults to three.
|
||||||
|
//
|
||||||
|
// By default, the diff control lines (those with ---, +++, or @@) are
|
||||||
|
// created with a trailing newline. This is helpful so that inputs
|
||||||
|
// created from file.readlines() result in diffs that are suitable for
|
||||||
|
// file.writelines() since both the inputs and outputs have trailing
|
||||||
|
// newlines.
|
||||||
|
//
|
||||||
|
// For inputs that do not have trailing newlines, set the lineterm
|
||||||
|
// argument to "" so that the output will be uniformly newline free.
|
||||||
|
//
|
||||||
|
// The unidiff format normally has a header for filenames and modification
|
||||||
|
// times. Any or all of these may be specified using strings for
|
||||||
|
// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
|
||||||
|
// The modification times are normally expressed in the ISO 8601 format.
|
||||||
|
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
|
||||||
|
buf := bufio.NewWriter(writer)
|
||||||
|
defer buf.Flush()
|
||||||
|
wf := func(format string, args ...interface{}) error {
|
||||||
|
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ws := func(s string) error {
|
||||||
|
_, err := buf.WriteString(s)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(diff.Eol) == 0 {
|
||||||
|
diff.Eol = "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
started := false
|
||||||
|
m := NewMatcher(diff.A, diff.B)
|
||||||
|
for _, g := range m.GetGroupedOpCodes(diff.Context) {
|
||||||
|
if !started {
|
||||||
|
started = true
|
||||||
|
fromDate := ""
|
||||||
|
if len(diff.FromDate) > 0 {
|
||||||
|
fromDate = "\t" + diff.FromDate
|
||||||
|
}
|
||||||
|
toDate := ""
|
||||||
|
if len(diff.ToDate) > 0 {
|
||||||
|
toDate = "\t" + diff.ToDate
|
||||||
|
}
|
||||||
|
if diff.FromFile != "" || diff.ToFile != "" {
|
||||||
|
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first, last := g[0], g[len(g)-1]
|
||||||
|
range1 := formatRangeUnified(first.I1, last.I2)
|
||||||
|
range2 := formatRangeUnified(first.J1, last.J2)
|
||||||
|
if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, c := range g {
|
||||||
|
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
||||||
|
if c.Tag == 'e' {
|
||||||
|
for _, line := range diff.A[i1:i2] {
|
||||||
|
if err := ws(" " + line); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.Tag == 'r' || c.Tag == 'd' {
|
||||||
|
for _, line := range diff.A[i1:i2] {
|
||||||
|
if err := ws("-" + line); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Tag == 'r' || c.Tag == 'i' {
|
||||||
|
for _, line := range diff.B[j1:j2] {
|
||||||
|
if err := ws("+" + line); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like WriteUnifiedDiff but returns the diff a string.
|
||||||
|
func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
err := WriteUnifiedDiff(w, diff)
|
||||||
|
return string(w.Bytes()), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert range to the "ed" format.
|
||||||
|
func formatRangeContext(start, stop int) string {
|
||||||
|
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
||||||
|
beginning := start + 1 // lines start numbering with one
|
||||||
|
length := stop - start
|
||||||
|
if length == 0 {
|
||||||
|
beginning -= 1 // empty ranges begin at line just before the range
|
||||||
|
}
|
||||||
|
if length <= 1 {
|
||||||
|
return fmt.Sprintf("%d", beginning)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContextDiff UnifiedDiff
|
||||||
|
|
||||||
|
// Compare two sequences of lines; generate the delta as a context diff.
|
||||||
|
//
|
||||||
|
// Context diffs are a compact way of showing line changes and a few
|
||||||
|
// lines of context. The number of context lines is set by diff.Context
|
||||||
|
// which defaults to three.
|
||||||
|
//
|
||||||
|
// By default, the diff control lines (those with *** or ---) are
|
||||||
|
// created with a trailing newline.
|
||||||
|
//
|
||||||
|
// For inputs that do not have trailing newlines, set the diff.Eol
|
||||||
|
// argument to "" so that the output will be uniformly newline free.
|
||||||
|
//
|
||||||
|
// The context diff format normally has a header for filenames and
|
||||||
|
// modification times. Any or all of these may be specified using
|
||||||
|
// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
|
||||||
|
// The modification times are normally expressed in the ISO 8601 format.
|
||||||
|
// If not specified, the strings default to blanks.
|
||||||
|
func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
||||||
|
buf := bufio.NewWriter(writer)
|
||||||
|
defer buf.Flush()
|
||||||
|
var diffErr error
|
||||||
|
wf := func(format string, args ...interface{}) {
|
||||||
|
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
||||||
|
if diffErr == nil && err != nil {
|
||||||
|
diffErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ws := func(s string) {
|
||||||
|
_, err := buf.WriteString(s)
|
||||||
|
if diffErr == nil && err != nil {
|
||||||
|
diffErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(diff.Eol) == 0 {
|
||||||
|
diff.Eol = "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := map[byte]string{
|
||||||
|
'i': "+ ",
|
||||||
|
'd': "- ",
|
||||||
|
'r': "! ",
|
||||||
|
'e': " ",
|
||||||
|
}
|
||||||
|
|
||||||
|
started := false
|
||||||
|
m := NewMatcher(diff.A, diff.B)
|
||||||
|
for _, g := range m.GetGroupedOpCodes(diff.Context) {
|
||||||
|
if !started {
|
||||||
|
started = true
|
||||||
|
fromDate := ""
|
||||||
|
if len(diff.FromDate) > 0 {
|
||||||
|
fromDate = "\t" + diff.FromDate
|
||||||
|
}
|
||||||
|
toDate := ""
|
||||||
|
if len(diff.ToDate) > 0 {
|
||||||
|
toDate = "\t" + diff.ToDate
|
||||||
|
}
|
||||||
|
if diff.FromFile != "" || diff.ToFile != "" {
|
||||||
|
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||||
|
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
first, last := g[0], g[len(g)-1]
|
||||||
|
ws("***************" + diff.Eol)
|
||||||
|
|
||||||
|
range1 := formatRangeContext(first.I1, last.I2)
|
||||||
|
wf("*** %s ****%s", range1, diff.Eol)
|
||||||
|
for _, c := range g {
|
||||||
|
if c.Tag == 'r' || c.Tag == 'd' {
|
||||||
|
for _, cc := range g {
|
||||||
|
if cc.Tag == 'i' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, line := range diff.A[cc.I1:cc.I2] {
|
||||||
|
ws(prefix[cc.Tag] + line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
range2 := formatRangeContext(first.J1, last.J2)
|
||||||
|
wf("--- %s ----%s", range2, diff.Eol)
|
||||||
|
for _, c := range g {
|
||||||
|
if c.Tag == 'r' || c.Tag == 'i' {
|
||||||
|
for _, cc := range g {
|
||||||
|
if cc.Tag == 'd' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, line := range diff.B[cc.J1:cc.J2] {
|
||||||
|
ws(prefix[cc.Tag] + line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return diffErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like WriteContextDiff but returns the diff a string.
|
||||||
|
func GetContextDiffString(diff ContextDiff) (string, error) {
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
err := WriteContextDiff(w, diff)
|
||||||
|
return string(w.Bytes()), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split a string on "\n" while preserving them. The output can be used
|
||||||
|
// as input for UnifiedDiff and ContextDiff structures.
|
||||||
|
func SplitLines(s string) []string {
|
||||||
|
lines := strings.SplitAfter(s, "\n")
|
||||||
|
lines[len(lines)-1] += "\n"
|
||||||
|
return lines
|
||||||
|
}
|
21
vendor/github.com/stretchr/testify/LICENSE
generated
vendored
Normal file
21
vendor/github.com/stretchr/testify/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
|
||||||
|
|
||||||
|
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.
|
394
vendor/github.com/stretchr/testify/assert/assertion_compare.go
generated
vendored
Normal file
394
vendor/github.com/stretchr/testify/assert/assertion_compare.go
generated
vendored
Normal file
|
@ -0,0 +1,394 @@
|
||||||
|
package assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CompareType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
compareLess CompareType = iota - 1
|
||||||
|
compareEqual
|
||||||
|
compareGreater
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
intType = reflect.TypeOf(int(1))
|
||||||
|
int8Type = reflect.TypeOf(int8(1))
|
||||||
|
int16Type = reflect.TypeOf(int16(1))
|
||||||
|
int32Type = reflect.TypeOf(int32(1))
|
||||||
|
int64Type = reflect.TypeOf(int64(1))
|
||||||
|
|
||||||
|
uintType = reflect.TypeOf(uint(1))
|
||||||
|
uint8Type = reflect.TypeOf(uint8(1))
|
||||||
|
uint16Type = reflect.TypeOf(uint16(1))
|
||||||
|
uint32Type = reflect.TypeOf(uint32(1))
|
||||||
|
uint64Type = reflect.TypeOf(uint64(1))
|
||||||
|
|
||||||
|
float32Type = reflect.TypeOf(float32(1))
|
||||||
|
float64Type = reflect.TypeOf(float64(1))
|
||||||
|
|
||||||
|
stringType = reflect.TypeOf("")
|
||||||
|
)
|
||||||
|
|
||||||
|
func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
|
||||||
|
obj1Value := reflect.ValueOf(obj1)
|
||||||
|
obj2Value := reflect.ValueOf(obj2)
|
||||||
|
|
||||||
|
// throughout this switch we try and avoid calling .Convert() if possible,
|
||||||
|
// as this has a pretty big performance impact
|
||||||
|
switch kind {
|
||||||
|
case reflect.Int:
|
||||||
|
{
|
||||||
|
intobj1, ok := obj1.(int)
|
||||||
|
if !ok {
|
||||||
|
intobj1 = obj1Value.Convert(intType).Interface().(int)
|
||||||
|
}
|
||||||
|
intobj2, ok := obj2.(int)
|
||||||
|
if !ok {
|
||||||
|
intobj2 = obj2Value.Convert(intType).Interface().(int)
|
||||||
|
}
|
||||||
|
if intobj1 > intobj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if intobj1 == intobj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if intobj1 < intobj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int8:
|
||||||
|
{
|
||||||
|
int8obj1, ok := obj1.(int8)
|
||||||
|
if !ok {
|
||||||
|
int8obj1 = obj1Value.Convert(int8Type).Interface().(int8)
|
||||||
|
}
|
||||||
|
int8obj2, ok := obj2.(int8)
|
||||||
|
if !ok {
|
||||||
|
int8obj2 = obj2Value.Convert(int8Type).Interface().(int8)
|
||||||
|
}
|
||||||
|
if int8obj1 > int8obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if int8obj1 == int8obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if int8obj1 < int8obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int16:
|
||||||
|
{
|
||||||
|
int16obj1, ok := obj1.(int16)
|
||||||
|
if !ok {
|
||||||
|
int16obj1 = obj1Value.Convert(int16Type).Interface().(int16)
|
||||||
|
}
|
||||||
|
int16obj2, ok := obj2.(int16)
|
||||||
|
if !ok {
|
||||||
|
int16obj2 = obj2Value.Convert(int16Type).Interface().(int16)
|
||||||
|
}
|
||||||
|
if int16obj1 > int16obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if int16obj1 == int16obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if int16obj1 < int16obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
{
|
||||||
|
int32obj1, ok := obj1.(int32)
|
||||||
|
if !ok {
|
||||||
|
int32obj1 = obj1Value.Convert(int32Type).Interface().(int32)
|
||||||
|
}
|
||||||
|
int32obj2, ok := obj2.(int32)
|
||||||
|
if !ok {
|
||||||
|
int32obj2 = obj2Value.Convert(int32Type).Interface().(int32)
|
||||||
|
}
|
||||||
|
if int32obj1 > int32obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if int32obj1 == int32obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if int32obj1 < int32obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int64:
|
||||||
|
{
|
||||||
|
int64obj1, ok := obj1.(int64)
|
||||||
|
if !ok {
|
||||||
|
int64obj1 = obj1Value.Convert(int64Type).Interface().(int64)
|
||||||
|
}
|
||||||
|
int64obj2, ok := obj2.(int64)
|
||||||
|
if !ok {
|
||||||
|
int64obj2 = obj2Value.Convert(int64Type).Interface().(int64)
|
||||||
|
}
|
||||||
|
if int64obj1 > int64obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if int64obj1 == int64obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if int64obj1 < int64obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint:
|
||||||
|
{
|
||||||
|
uintobj1, ok := obj1.(uint)
|
||||||
|
if !ok {
|
||||||
|
uintobj1 = obj1Value.Convert(uintType).Interface().(uint)
|
||||||
|
}
|
||||||
|
uintobj2, ok := obj2.(uint)
|
||||||
|
if !ok {
|
||||||
|
uintobj2 = obj2Value.Convert(uintType).Interface().(uint)
|
||||||
|
}
|
||||||
|
if uintobj1 > uintobj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if uintobj1 == uintobj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if uintobj1 < uintobj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint8:
|
||||||
|
{
|
||||||
|
uint8obj1, ok := obj1.(uint8)
|
||||||
|
if !ok {
|
||||||
|
uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8)
|
||||||
|
}
|
||||||
|
uint8obj2, ok := obj2.(uint8)
|
||||||
|
if !ok {
|
||||||
|
uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8)
|
||||||
|
}
|
||||||
|
if uint8obj1 > uint8obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if uint8obj1 == uint8obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if uint8obj1 < uint8obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
{
|
||||||
|
uint16obj1, ok := obj1.(uint16)
|
||||||
|
if !ok {
|
||||||
|
uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16)
|
||||||
|
}
|
||||||
|
uint16obj2, ok := obj2.(uint16)
|
||||||
|
if !ok {
|
||||||
|
uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16)
|
||||||
|
}
|
||||||
|
if uint16obj1 > uint16obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if uint16obj1 == uint16obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if uint16obj1 < uint16obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
{
|
||||||
|
uint32obj1, ok := obj1.(uint32)
|
||||||
|
if !ok {
|
||||||
|
uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32)
|
||||||
|
}
|
||||||
|
uint32obj2, ok := obj2.(uint32)
|
||||||
|
if !ok {
|
||||||
|
uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32)
|
||||||
|
}
|
||||||
|
if uint32obj1 > uint32obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if uint32obj1 == uint32obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if uint32obj1 < uint32obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint64:
|
||||||
|
{
|
||||||
|
uint64obj1, ok := obj1.(uint64)
|
||||||
|
if !ok {
|
||||||
|
uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64)
|
||||||
|
}
|
||||||
|
uint64obj2, ok := obj2.(uint64)
|
||||||
|
if !ok {
|
||||||
|
uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64)
|
||||||
|
}
|
||||||
|
if uint64obj1 > uint64obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if uint64obj1 == uint64obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if uint64obj1 < uint64obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Float32:
|
||||||
|
{
|
||||||
|
float32obj1, ok := obj1.(float32)
|
||||||
|
if !ok {
|
||||||
|
float32obj1 = obj1Value.Convert(float32Type).Interface().(float32)
|
||||||
|
}
|
||||||
|
float32obj2, ok := obj2.(float32)
|
||||||
|
if !ok {
|
||||||
|
float32obj2 = obj2Value.Convert(float32Type).Interface().(float32)
|
||||||
|
}
|
||||||
|
if float32obj1 > float32obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if float32obj1 == float32obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if float32obj1 < float32obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Float64:
|
||||||
|
{
|
||||||
|
float64obj1, ok := obj1.(float64)
|
||||||
|
if !ok {
|
||||||
|
float64obj1 = obj1Value.Convert(float64Type).Interface().(float64)
|
||||||
|
}
|
||||||
|
float64obj2, ok := obj2.(float64)
|
||||||
|
if !ok {
|
||||||
|
float64obj2 = obj2Value.Convert(float64Type).Interface().(float64)
|
||||||
|
}
|
||||||
|
if float64obj1 > float64obj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if float64obj1 == float64obj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if float64obj1 < float64obj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
{
|
||||||
|
stringobj1, ok := obj1.(string)
|
||||||
|
if !ok {
|
||||||
|
stringobj1 = obj1Value.Convert(stringType).Interface().(string)
|
||||||
|
}
|
||||||
|
stringobj2, ok := obj2.(string)
|
||||||
|
if !ok {
|
||||||
|
stringobj2 = obj2Value.Convert(stringType).Interface().(string)
|
||||||
|
}
|
||||||
|
if stringobj1 > stringobj2 {
|
||||||
|
return compareGreater, true
|
||||||
|
}
|
||||||
|
if stringobj1 == stringobj2 {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
if stringobj1 < stringobj2 {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return compareEqual, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Greater asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// assert.Greater(t, 2, 1)
|
||||||
|
// assert.Greater(t, float64(2), float64(1))
|
||||||
|
// assert.Greater(t, "b", "a")
|
||||||
|
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqual asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.GreaterOrEqual(t, 2, 1)
|
||||||
|
// assert.GreaterOrEqual(t, 2, 2)
|
||||||
|
// assert.GreaterOrEqual(t, "b", "a")
|
||||||
|
// assert.GreaterOrEqual(t, "b", "b")
|
||||||
|
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// assert.Less(t, 1, 2)
|
||||||
|
// assert.Less(t, float64(1), float64(2))
|
||||||
|
// assert.Less(t, "a", "b")
|
||||||
|
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqual asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.LessOrEqual(t, 1, 2)
|
||||||
|
// assert.LessOrEqual(t, 2, 2)
|
||||||
|
// assert.LessOrEqual(t, "a", "b")
|
||||||
|
// assert.LessOrEqual(t, "b", "b")
|
||||||
|
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Positive asserts that the specified element is positive
|
||||||
|
//
|
||||||
|
// assert.Positive(t, 1)
|
||||||
|
// assert.Positive(t, 1.23)
|
||||||
|
func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
zero := reflect.Zero(reflect.TypeOf(e))
|
||||||
|
return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negative asserts that the specified element is negative
|
||||||
|
//
|
||||||
|
// assert.Negative(t, -1)
|
||||||
|
// assert.Negative(t, -1.23)
|
||||||
|
func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
zero := reflect.Zero(reflect.TypeOf(e))
|
||||||
|
return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
e1Kind := reflect.ValueOf(e1).Kind()
|
||||||
|
e2Kind := reflect.ValueOf(e2).Kind()
|
||||||
|
if e1Kind != e2Kind {
|
||||||
|
return Fail(t, "Elements should be the same type", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
compareResult, isComparable := compare(e1, e2, e1Kind)
|
||||||
|
if !isComparable {
|
||||||
|
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !containsValue(allowedComparesResults, compareResult) {
|
||||||
|
return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsValue(values []CompareType, value CompareType) bool {
|
||||||
|
for _, v := range values {
|
||||||
|
if v == value {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
741
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
Normal file
741
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
Normal file
|
@ -0,0 +1,741 @@
|
||||||
|
/*
|
||||||
|
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
|
||||||
|
* THIS FILE MUST NOT BE EDITED BY HAND
|
||||||
|
*/
|
||||||
|
|
||||||
|
package assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
http "net/http"
|
||||||
|
url "net/url"
|
||||||
|
time "time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Conditionf uses a Comparison to assert a complex condition.
|
||||||
|
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Condition(t, comp, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Containsf asserts that the specified string, list(array, slice...) or map contains the
|
||||||
|
// specified substring or element.
|
||||||
|
//
|
||||||
|
// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
|
||||||
|
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
|
||||||
|
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
|
||||||
|
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||||
|
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||||
|
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return DirExists(t, path, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
|
||||||
|
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
|
||||||
|
// the number of appearances of each of them in both lists should match.
|
||||||
|
//
|
||||||
|
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
|
||||||
|
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
||||||
|
// a slice or a channel with len == 0.
|
||||||
|
//
|
||||||
|
// assert.Emptyf(t, obj, "error message %s", "formatted")
|
||||||
|
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Empty(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equalf asserts that two objects are equal.
|
||||||
|
//
|
||||||
|
// assert.Equalf(t, 123, 123, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Pointer variable equality is determined based on the equality of the
|
||||||
|
// referenced values (as opposed to the memory addresses). Function equality
|
||||||
|
// cannot be determined and will always fail.
|
||||||
|
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
|
||||||
|
// and that it is equal to the provided error.
|
||||||
|
//
|
||||||
|
// actualObj, err := SomeFunction()
|
||||||
|
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
|
||||||
|
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EqualValuesf asserts that two objects are equal or convertable to the same types
|
||||||
|
// and equal.
|
||||||
|
//
|
||||||
|
// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
|
||||||
|
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf asserts that a function returned an error (i.e. not `nil`).
|
||||||
|
//
|
||||||
|
// actualObj, err := SomeFunction()
|
||||||
|
// if assert.Errorf(t, err, "error message %s", "formatted") {
|
||||||
|
// assert.Equal(t, expectedErrorf, err)
|
||||||
|
// }
|
||||||
|
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Error(t, err, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
|
||||||
|
// This is a wrapper for errors.As.
|
||||||
|
func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorIsf asserts that at least one of the errors in err's chain matches target.
|
||||||
|
// This is a wrapper for errors.Is.
|
||||||
|
func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventuallyf asserts that given condition will be met in waitFor time,
|
||||||
|
// periodically checking target function each tick.
|
||||||
|
//
|
||||||
|
// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||||
|
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exactlyf asserts that two objects are equal in value and type.
|
||||||
|
//
|
||||||
|
// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
|
||||||
|
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failf reports a failure through
|
||||||
|
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FailNowf fails test
|
||||||
|
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Falsef asserts that the specified value is false.
|
||||||
|
//
|
||||||
|
// assert.Falsef(t, myBool, "error message %s", "formatted")
|
||||||
|
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return False(t, value, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||||
|
// the path points to a directory or there is an error when trying to check the file.
|
||||||
|
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return FileExists(t, path, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Greaterf asserts that the first element is greater than the second
|
||||||
|
//
|
||||||
|
// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
|
||||||
|
// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
|
||||||
|
// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
|
||||||
|
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
|
||||||
|
// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
|
||||||
|
// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
|
||||||
|
// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
|
||||||
|
func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPBodyContainsf asserts that a specified handler returns a
|
||||||
|
// body that contains a string.
|
||||||
|
//
|
||||||
|
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
||||||
|
// body that does not contain a string.
|
||||||
|
//
|
||||||
|
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPErrorf asserts that a specified handler returns an error status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPSuccessf asserts that a specified handler returns a success status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementsf asserts that an object is implemented by the specified interface.
|
||||||
|
//
|
||||||
|
// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
|
||||||
|
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||||
|
//
|
||||||
|
// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||||
|
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
||||||
|
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
||||||
|
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
||||||
|
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
||||||
|
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDecreasingf asserts that the collection is decreasing
|
||||||
|
//
|
||||||
|
// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted")
|
||||||
|
// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted")
|
||||||
|
// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
|
||||||
|
func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return IsDecreasing(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsIncreasingf asserts that the collection is increasing
|
||||||
|
//
|
||||||
|
// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted")
|
||||||
|
// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted")
|
||||||
|
// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
|
||||||
|
func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return IsIncreasing(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNonDecreasingf asserts that the collection is not decreasing
|
||||||
|
//
|
||||||
|
// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted")
|
||||||
|
// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted")
|
||||||
|
// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
|
||||||
|
func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNonIncreasingf asserts that the collection is not increasing
|
||||||
|
//
|
||||||
|
// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted")
|
||||||
|
// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted")
|
||||||
|
// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
|
||||||
|
func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTypef asserts that the specified objects are of the same type.
|
||||||
|
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONEqf asserts that two JSON strings are equivalent.
|
||||||
|
//
|
||||||
|
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
||||||
|
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lenf asserts that the specified object has specific length.
|
||||||
|
// Lenf also fails if the object has a type that len() not accept.
|
||||||
|
//
|
||||||
|
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
|
||||||
|
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Len(t, object, length, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lessf asserts that the first element is less than the second
|
||||||
|
//
|
||||||
|
// assert.Lessf(t, 1, 2, "error message %s", "formatted")
|
||||||
|
// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
|
||||||
|
// assert.Lessf(t, "a", "b", "error message %s", "formatted")
|
||||||
|
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LessOrEqualf asserts that the first element is less than or equal to the second
|
||||||
|
//
|
||||||
|
// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
|
||||||
|
// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
|
||||||
|
// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
|
||||||
|
// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
|
||||||
|
func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negativef asserts that the specified element is negative
|
||||||
|
//
|
||||||
|
// assert.Negativef(t, -1, "error message %s", "formatted")
|
||||||
|
// assert.Negativef(t, -1.23, "error message %s", "formatted")
|
||||||
|
func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Negative(t, e, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||||
|
// periodically checking the target function each tick.
|
||||||
|
//
|
||||||
|
// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||||
|
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nilf asserts that the specified object is nil.
|
||||||
|
//
|
||||||
|
// assert.Nilf(t, err, "error message %s", "formatted")
|
||||||
|
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Nil(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||||
|
// It fails if the path points to an existing _directory_ only.
|
||||||
|
func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NoDirExists(t, path, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoErrorf asserts that a function returned no error (i.e. `nil`).
|
||||||
|
//
|
||||||
|
// actualObj, err := SomeFunction()
|
||||||
|
// if assert.NoErrorf(t, err, "error message %s", "formatted") {
|
||||||
|
// assert.Equal(t, expectedObj, actualObj)
|
||||||
|
// }
|
||||||
|
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NoError(t, err, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||||
|
// if the path points to an existing _file_ only.
|
||||||
|
func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NoFileExists(t, path, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||||
|
// specified substring or element.
|
||||||
|
//
|
||||||
|
// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
|
||||||
|
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
|
||||||
|
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
|
||||||
|
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
|
||||||
|
// a slice or a channel with len == 0.
|
||||||
|
//
|
||||||
|
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
|
||||||
|
// assert.Equal(t, "two", obj[1])
|
||||||
|
// }
|
||||||
|
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotEqualf asserts that the specified values are NOT equal.
|
||||||
|
//
|
||||||
|
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Pointer variable equality is determined based on the equality of the
|
||||||
|
// referenced values (as opposed to the memory addresses).
|
||||||
|
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
|
||||||
|
//
|
||||||
|
// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
|
||||||
|
func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotErrorIsf asserts that at none of the errors in err's chain matches target.
|
||||||
|
// This is a wrapper for errors.Is.
|
||||||
|
func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotNilf asserts that the specified object is not nil.
|
||||||
|
//
|
||||||
|
// assert.NotNilf(t, err, "error message %s", "formatted")
|
||||||
|
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotNil(t, object, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
|
||||||
|
//
|
||||||
|
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
|
||||||
|
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotPanics(t, f, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotRegexpf asserts that a specified regexp does not match a string.
|
||||||
|
//
|
||||||
|
// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
|
||||||
|
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
|
||||||
|
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotSamef asserts that two pointers do not reference the same object.
|
||||||
|
//
|
||||||
|
// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
||||||
|
// elements given in the specified subset(array, slice...).
|
||||||
|
//
|
||||||
|
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||||
|
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotZerof asserts that i is not the zero value for its type.
|
||||||
|
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotZero(t, i, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
|
||||||
|
//
|
||||||
|
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
|
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Panics(t, f, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||||
|
// panics, and that the recovered panic value is an error that satisfies the
|
||||||
|
// EqualError comparison.
|
||||||
|
//
|
||||||
|
// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
|
func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
|
||||||
|
// the recovered panic value equals the expected panic value.
|
||||||
|
//
|
||||||
|
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
|
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Positivef asserts that the specified element is positive
|
||||||
|
//
|
||||||
|
// assert.Positivef(t, 1, "error message %s", "formatted")
|
||||||
|
// assert.Positivef(t, 1.23, "error message %s", "formatted")
|
||||||
|
func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Positive(t, e, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regexpf asserts that a specified regexp matches a string.
|
||||||
|
//
|
||||||
|
// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
|
||||||
|
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
|
||||||
|
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samef asserts that two pointers reference the same object.
|
||||||
|
//
|
||||||
|
// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
|
||||||
|
//
|
||||||
|
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||||
|
// determined based on the equality of both type and value.
|
||||||
|
func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subsetf asserts that the specified list(array, slice...) contains all
|
||||||
|
// elements given in the specified subset(array, slice...).
|
||||||
|
//
|
||||||
|
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||||
|
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truef asserts that the specified value is true.
|
||||||
|
//
|
||||||
|
// assert.Truef(t, myBool, "error message %s", "formatted")
|
||||||
|
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return True(t, value, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithinDurationf asserts that the two times are within duration delta of each other.
|
||||||
|
//
|
||||||
|
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
||||||
|
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||||
|
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zerof asserts that i is the zero value for its type.
|
||||||
|
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return Zero(t, i, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
5
vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
generated
vendored
Normal file
5
vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{{.CommentFormat}}
|
||||||
|
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok { h.Helper() }
|
||||||
|
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
|
||||||
|
}
|
1470
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
Normal file
1470
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
5
vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
generated
vendored
Normal file
5
vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{{.CommentWithoutT "a"}}
|
||||||
|
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok { h.Helper() }
|
||||||
|
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
||||||
|
}
|
81
vendor/github.com/stretchr/testify/assert/assertion_order.go
generated
vendored
Normal file
81
vendor/github.com/stretchr/testify/assert/assertion_order.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// isOrdered checks that collection contains orderable elements.
|
||||||
|
func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool {
|
||||||
|
objKind := reflect.TypeOf(object).Kind()
|
||||||
|
if objKind != reflect.Slice && objKind != reflect.Array {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
objValue := reflect.ValueOf(object)
|
||||||
|
objLen := objValue.Len()
|
||||||
|
|
||||||
|
if objLen <= 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
value := objValue.Index(0)
|
||||||
|
valueInterface := value.Interface()
|
||||||
|
firstValueKind := value.Kind()
|
||||||
|
|
||||||
|
for i := 1; i < objLen; i++ {
|
||||||
|
prevValue := value
|
||||||
|
prevValueInterface := valueInterface
|
||||||
|
|
||||||
|
value = objValue.Index(i)
|
||||||
|
valueInterface = value.Interface()
|
||||||
|
|
||||||
|
compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind)
|
||||||
|
|
||||||
|
if !isComparable {
|
||||||
|
return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !containsValue(allowedComparesResults, compareResult) {
|
||||||
|
return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsIncreasing asserts that the collection is increasing
|
||||||
|
//
|
||||||
|
// assert.IsIncreasing(t, []int{1, 2, 3})
|
||||||
|
// assert.IsIncreasing(t, []float{1, 2})
|
||||||
|
// assert.IsIncreasing(t, []string{"a", "b"})
|
||||||
|
func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNonIncreasing asserts that the collection is not increasing
|
||||||
|
//
|
||||||
|
// assert.IsNonIncreasing(t, []int{2, 1, 1})
|
||||||
|
// assert.IsNonIncreasing(t, []float{2, 1})
|
||||||
|
// assert.IsNonIncreasing(t, []string{"b", "a"})
|
||||||
|
func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDecreasing asserts that the collection is decreasing
|
||||||
|
//
|
||||||
|
// assert.IsDecreasing(t, []int{2, 1, 0})
|
||||||
|
// assert.IsDecreasing(t, []float{2, 1})
|
||||||
|
// assert.IsDecreasing(t, []string{"b", "a"})
|
||||||
|
func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNonDecreasing asserts that the collection is not decreasing
|
||||||
|
//
|
||||||
|
// assert.IsNonDecreasing(t, []int{1, 1, 2})
|
||||||
|
// assert.IsNonDecreasing(t, []float{1, 2})
|
||||||
|
// assert.IsNonDecreasing(t, []string{"a", "b"})
|
||||||
|
func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs)
|
||||||
|
}
|
1774
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
Normal file
1774
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
45
vendor/github.com/stretchr/testify/assert/doc.go
generated
vendored
Normal file
45
vendor/github.com/stretchr/testify/assert/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
|
||||||
|
//
|
||||||
|
// Example Usage
|
||||||
|
//
|
||||||
|
// The following is a complete example using assert in a standard test function:
|
||||||
|
// import (
|
||||||
|
// "testing"
|
||||||
|
// "github.com/stretchr/testify/assert"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func TestSomething(t *testing.T) {
|
||||||
|
//
|
||||||
|
// var a string = "Hello"
|
||||||
|
// var b string = "Hello"
|
||||||
|
//
|
||||||
|
// assert.Equal(t, a, b, "The two words should be the same.")
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if you assert many times, use the format below:
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "testing"
|
||||||
|
// "github.com/stretchr/testify/assert"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func TestSomething(t *testing.T) {
|
||||||
|
// assert := assert.New(t)
|
||||||
|
//
|
||||||
|
// var a string = "Hello"
|
||||||
|
// var b string = "Hello"
|
||||||
|
//
|
||||||
|
// assert.Equal(a, b, "The two words should be the same.")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Assertions
|
||||||
|
//
|
||||||
|
// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
|
||||||
|
// All assertion functions take, as the first argument, the `*testing.T` object provided by the
|
||||||
|
// testing framework. This allows the assertion funcs to write the failings and other details to
|
||||||
|
// the correct place.
|
||||||
|
//
|
||||||
|
// Every assertion function also takes an optional string message as the final argument,
|
||||||
|
// allowing custom error messages to be appended to the message the assertion method outputs.
|
||||||
|
package assert
|
10
vendor/github.com/stretchr/testify/assert/errors.go
generated
vendored
Normal file
10
vendor/github.com/stretchr/testify/assert/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnError is an error instance useful for testing. If the code does not care
|
||||||
|
// about error specifics, and only needs to return the error for example, this
|
||||||
|
// error should be used to make the test code more readable.
|
||||||
|
var AnError = errors.New("assert.AnError general error for testing")
|
16
vendor/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
Normal file
16
vendor/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package assert
|
||||||
|
|
||||||
|
// Assertions provides assertion methods around the
|
||||||
|
// TestingT interface.
|
||||||
|
type Assertions struct {
|
||||||
|
t TestingT
|
||||||
|
}
|
||||||
|
|
||||||
|
// New makes a new Assertions object for the specified TestingT.
|
||||||
|
func New(t TestingT) *Assertions {
|
||||||
|
return &Assertions{
|
||||||
|
t: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs"
|
162
vendor/github.com/stretchr/testify/assert/http_assertions.go
generated
vendored
Normal file
162
vendor/github.com/stretchr/testify/assert/http_assertions.go
generated
vendored
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
package assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// httpCode is a helper that returns HTTP code of the response. It returns -1 and
|
||||||
|
// an error if building a new request fails.
|
||||||
|
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest(method, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
req.URL.RawQuery = values.Encode()
|
||||||
|
handler(w, req)
|
||||||
|
return w.Code, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPSuccess asserts that a specified handler returns a success status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
code, err := httpCode(handler, method, url, values)
|
||||||
|
if err != nil {
|
||||||
|
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
|
||||||
|
if !isSuccessCode {
|
||||||
|
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code))
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSuccessCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPRedirect asserts that a specified handler returns a redirect status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
code, err := httpCode(handler, method, url, values)
|
||||||
|
if err != nil {
|
||||||
|
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
|
||||||
|
if !isRedirectCode {
|
||||||
|
Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code))
|
||||||
|
}
|
||||||
|
|
||||||
|
return isRedirectCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPError asserts that a specified handler returns an error status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
code, err := httpCode(handler, method, url, values)
|
||||||
|
if err != nil {
|
||||||
|
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
isErrorCode := code >= http.StatusBadRequest
|
||||||
|
if !isErrorCode {
|
||||||
|
Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code))
|
||||||
|
}
|
||||||
|
|
||||||
|
return isErrorCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPStatusCode asserts that a specified handler returns a specified status code.
|
||||||
|
//
|
||||||
|
// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
code, err := httpCode(handler, method, url, values)
|
||||||
|
if err != nil {
|
||||||
|
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
successful := code == statuscode
|
||||||
|
if !successful {
|
||||||
|
Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code))
|
||||||
|
}
|
||||||
|
|
||||||
|
return successful
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPBody is a helper that returns HTTP body of the response. It returns
|
||||||
|
// empty string if building a new request fails.
|
||||||
|
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
handler(w, req)
|
||||||
|
return w.Body.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPBodyContains asserts that a specified handler returns a
|
||||||
|
// body that contains a string.
|
||||||
|
//
|
||||||
|
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
body := HTTPBody(handler, method, url, values)
|
||||||
|
|
||||||
|
contains := strings.Contains(body, fmt.Sprint(str))
|
||||||
|
if !contains {
|
||||||
|
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return contains
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPBodyNotContains asserts that a specified handler returns a
|
||||||
|
// body that does not contain a string.
|
||||||
|
//
|
||||||
|
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
|
//
|
||||||
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
|
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
body := HTTPBody(handler, method, url, values)
|
||||||
|
|
||||||
|
contains := strings.Contains(body, fmt.Sprint(str))
|
||||||
|
if contains {
|
||||||
|
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return !contains
|
||||||
|
}
|
28
vendor/github.com/stretchr/testify/require/doc.go
generated
vendored
Normal file
28
vendor/github.com/stretchr/testify/require/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Package require implements the same assertions as the `assert` package but
|
||||||
|
// stops test execution when a test fails.
|
||||||
|
//
|
||||||
|
// Example Usage
|
||||||
|
//
|
||||||
|
// The following is a complete example using require in a standard test function:
|
||||||
|
// import (
|
||||||
|
// "testing"
|
||||||
|
// "github.com/stretchr/testify/require"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func TestSomething(t *testing.T) {
|
||||||
|
//
|
||||||
|
// var a string = "Hello"
|
||||||
|
// var b string = "Hello"
|
||||||
|
//
|
||||||
|
// require.Equal(t, a, b, "The two words should be the same.")
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Assertions
|
||||||
|
//
|
||||||
|
// The `require` package have same global functions as in the `assert` package,
|
||||||
|
// but instead of returning a boolean result they call `t.FailNow()`.
|
||||||
|
//
|
||||||
|
// Every assertion function also takes an optional string message as the final argument,
|
||||||
|
// allowing custom error messages to be appended to the message the assertion method outputs.
|
||||||
|
package require
|
16
vendor/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
Normal file
16
vendor/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package require
|
||||||
|
|
||||||
|
// Assertions provides assertion methods around the
|
||||||
|
// TestingT interface.
|
||||||
|
type Assertions struct {
|
||||||
|
t TestingT
|
||||||
|
}
|
||||||
|
|
||||||
|
// New makes a new Assertions object for the specified TestingT.
|
||||||
|
func New(t TestingT) *Assertions {
|
||||||
|
return &Assertions{
|
||||||
|
t: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs"
|
1879
vendor/github.com/stretchr/testify/require/require.go
generated
vendored
Normal file
1879
vendor/github.com/stretchr/testify/require/require.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
vendor/github.com/stretchr/testify/require/require.go.tmpl
generated
vendored
Normal file
6
vendor/github.com/stretchr/testify/require/require.go.tmpl
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{{.Comment}}
|
||||||
|
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
||||||
|
if h, ok := t.(tHelper); ok { h.Helper() }
|
||||||
|
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
|
||||||
|
t.FailNow()
|
||||||
|
}
|
1471
vendor/github.com/stretchr/testify/require/require_forward.go
generated
vendored
Normal file
1471
vendor/github.com/stretchr/testify/require/require_forward.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
5
vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
generated
vendored
Normal file
5
vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{{.CommentWithoutT "a"}}
|
||||||
|
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok { h.Helper() }
|
||||||
|
{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
||||||
|
}
|
29
vendor/github.com/stretchr/testify/require/requirements.go
generated
vendored
Normal file
29
vendor/github.com/stretchr/testify/require/requirements.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package require
|
||||||
|
|
||||||
|
// TestingT is an interface wrapper around *testing.T
|
||||||
|
type TestingT interface {
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
type tHelper interface {
|
||||||
|
Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
|
||||||
|
|
||||||
|
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
|
||||||
|
|
||||||
|
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type BoolAssertionFunc func(TestingT, bool, ...interface{})
|
||||||
|
|
||||||
|
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ErrorAssertionFunc func(TestingT, error, ...interface{})
|
||||||
|
|
||||||
|
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs"
|
50
vendor/gopkg.in/yaml.v3/LICENSE
generated
vendored
Normal file
50
vendor/gopkg.in/yaml.v3/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
This project is covered by two different licenses: MIT and Apache.
|
||||||
|
|
||||||
|
#### MIT License ####
|
||||||
|
|
||||||
|
The following files were ported to Go from C files of libyaml, and thus
|
||||||
|
are still covered by their original MIT license, with the additional
|
||||||
|
copyright staring in 2011 when the project was ported over:
|
||||||
|
|
||||||
|
apic.go emitterc.go parserc.go readerc.go scannerc.go
|
||||||
|
writerc.go yamlh.go yamlprivateh.go
|
||||||
|
|
||||||
|
Copyright (c) 2006-2010 Kirill Simonov
|
||||||
|
Copyright (c) 2006-2011 Kirill Simonov
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
### Apache License ###
|
||||||
|
|
||||||
|
All the remaining project files are covered by the Apache license:
|
||||||
|
|
||||||
|
Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
13
vendor/gopkg.in/yaml.v3/NOTICE
generated
vendored
Normal file
13
vendor/gopkg.in/yaml.v3/NOTICE
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2011-2016 Canonical Ltd.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
150
vendor/gopkg.in/yaml.v3/README.md
generated
vendored
Normal file
150
vendor/gopkg.in/yaml.v3/README.md
generated
vendored
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
# YAML support for the Go language
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
The yaml package enables Go programs to comfortably encode and decode YAML
|
||||||
|
values. It was developed within [Canonical](https://www.canonical.com) as
|
||||||
|
part of the [juju](https://juju.ubuntu.com) project, and is based on a
|
||||||
|
pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
|
||||||
|
C library to parse and generate YAML data quickly and reliably.
|
||||||
|
|
||||||
|
Compatibility
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The yaml package supports most of YAML 1.2, but preserves some behavior
|
||||||
|
from 1.1 for backwards compatibility.
|
||||||
|
|
||||||
|
Specifically, as of v3 of the yaml package:
|
||||||
|
|
||||||
|
- YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being
|
||||||
|
decoded into a typed bool value. Otherwise they behave as a string. Booleans
|
||||||
|
in YAML 1.2 are _true/false_ only.
|
||||||
|
- Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_
|
||||||
|
as specified in YAML 1.2, because most parsers still use the old format.
|
||||||
|
Octals in the _0o777_ format are supported though, so new files work.
|
||||||
|
- Does not support base-60 floats. These are gone from YAML 1.2, and were
|
||||||
|
actually never supported by this package as it's clearly a poor choice.
|
||||||
|
|
||||||
|
and offers backwards
|
||||||
|
compatibility with YAML 1.1 in some cases.
|
||||||
|
1.2, including support for
|
||||||
|
anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
|
||||||
|
implemented, and base-60 floats from YAML 1.1 are purposefully not
|
||||||
|
supported since they're a poor design and are gone in YAML 1.2.
|
||||||
|
|
||||||
|
Installation and usage
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The import path for the package is *gopkg.in/yaml.v3*.
|
||||||
|
|
||||||
|
To install it, run:
|
||||||
|
|
||||||
|
go get gopkg.in/yaml.v3
|
||||||
|
|
||||||
|
API documentation
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
If opened in a browser, the import path itself leads to the API documentation:
|
||||||
|
|
||||||
|
- [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3)
|
||||||
|
|
||||||
|
API stability
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in).
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
The yaml package is licensed under the MIT and Apache License 2.0 licenses.
|
||||||
|
Please see the LICENSE file for details.
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
```Go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var data = `
|
||||||
|
a: Easy!
|
||||||
|
b:
|
||||||
|
c: 2
|
||||||
|
d: [3, 4]
|
||||||
|
`
|
||||||
|
|
||||||
|
// Note: struct fields must be public in order for unmarshal to
|
||||||
|
// correctly populate the data.
|
||||||
|
type T struct {
|
||||||
|
A string
|
||||||
|
B struct {
|
||||||
|
RenamedC int `yaml:"c"`
|
||||||
|
D []int `yaml:",flow"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
t := T{}
|
||||||
|
|
||||||
|
err := yaml.Unmarshal([]byte(data), &t)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- t:\n%v\n\n", t)
|
||||||
|
|
||||||
|
d, err := yaml.Marshal(&t)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- t dump:\n%s\n\n", string(d))
|
||||||
|
|
||||||
|
m := make(map[interface{}]interface{})
|
||||||
|
|
||||||
|
err = yaml.Unmarshal([]byte(data), &m)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- m:\n%v\n\n", m)
|
||||||
|
|
||||||
|
d, err = yaml.Marshal(&m)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- m dump:\n%s\n\n", string(d))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This example will generate the following output:
|
||||||
|
|
||||||
|
```
|
||||||
|
--- t:
|
||||||
|
{Easy! {2 [3 4]}}
|
||||||
|
|
||||||
|
--- t dump:
|
||||||
|
a: Easy!
|
||||||
|
b:
|
||||||
|
c: 2
|
||||||
|
d: [3, 4]
|
||||||
|
|
||||||
|
|
||||||
|
--- m:
|
||||||
|
map[a:Easy! b:map[c:2 d:[3 4]]]
|
||||||
|
|
||||||
|
--- m dump:
|
||||||
|
a: Easy!
|
||||||
|
b:
|
||||||
|
c: 2
|
||||||
|
d:
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
```
|
||||||
|
|
747
vendor/gopkg.in/yaml.v3/apic.go
generated
vendored
Normal file
747
vendor/gopkg.in/yaml.v3/apic.go
generated
vendored
Normal file
|
@ -0,0 +1,747 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
// Copyright (c) 2006-2010 Kirill Simonov
|
||||||
|
//
|
||||||
|
// 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 yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
|
||||||
|
//fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
|
||||||
|
|
||||||
|
// Check if we can move the queue at the beginning of the buffer.
|
||||||
|
if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
|
||||||
|
if parser.tokens_head != len(parser.tokens) {
|
||||||
|
copy(parser.tokens, parser.tokens[parser.tokens_head:])
|
||||||
|
}
|
||||||
|
parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
|
||||||
|
parser.tokens_head = 0
|
||||||
|
}
|
||||||
|
parser.tokens = append(parser.tokens, *token)
|
||||||
|
if pos < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
|
||||||
|
parser.tokens[parser.tokens_head+pos] = *token
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new parser object.
|
||||||
|
func yaml_parser_initialize(parser *yaml_parser_t) bool {
|
||||||
|
*parser = yaml_parser_t{
|
||||||
|
raw_buffer: make([]byte, 0, input_raw_buffer_size),
|
||||||
|
buffer: make([]byte, 0, input_buffer_size),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy a parser object.
|
||||||
|
func yaml_parser_delete(parser *yaml_parser_t) {
|
||||||
|
*parser = yaml_parser_t{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String read handler.
|
||||||
|
func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
|
||||||
|
if parser.input_pos == len(parser.input) {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
n = copy(buffer, parser.input[parser.input_pos:])
|
||||||
|
parser.input_pos += n
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reader read handler.
|
||||||
|
func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
|
||||||
|
return parser.input_reader.Read(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a string input.
|
||||||
|
func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
|
||||||
|
if parser.read_handler != nil {
|
||||||
|
panic("must set the input source only once")
|
||||||
|
}
|
||||||
|
parser.read_handler = yaml_string_read_handler
|
||||||
|
parser.input = input
|
||||||
|
parser.input_pos = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a file input.
|
||||||
|
func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
|
||||||
|
if parser.read_handler != nil {
|
||||||
|
panic("must set the input source only once")
|
||||||
|
}
|
||||||
|
parser.read_handler = yaml_reader_read_handler
|
||||||
|
parser.input_reader = r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the source encoding.
|
||||||
|
func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
|
||||||
|
if parser.encoding != yaml_ANY_ENCODING {
|
||||||
|
panic("must set the encoding only once")
|
||||||
|
}
|
||||||
|
parser.encoding = encoding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new emitter object.
|
||||||
|
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
|
||||||
|
*emitter = yaml_emitter_t{
|
||||||
|
buffer: make([]byte, output_buffer_size),
|
||||||
|
raw_buffer: make([]byte, 0, output_raw_buffer_size),
|
||||||
|
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
|
||||||
|
events: make([]yaml_event_t, 0, initial_queue_size),
|
||||||
|
best_width: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy an emitter object.
|
||||||
|
func yaml_emitter_delete(emitter *yaml_emitter_t) {
|
||||||
|
*emitter = yaml_emitter_t{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String write handler.
|
||||||
|
func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
|
||||||
|
*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// yaml_writer_write_handler uses emitter.output_writer to write the
|
||||||
|
// emitted text.
|
||||||
|
func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
|
||||||
|
_, err := emitter.output_writer.Write(buffer)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a string output.
|
||||||
|
func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
|
||||||
|
if emitter.write_handler != nil {
|
||||||
|
panic("must set the output target only once")
|
||||||
|
}
|
||||||
|
emitter.write_handler = yaml_string_write_handler
|
||||||
|
emitter.output_buffer = output_buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a file output.
|
||||||
|
func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
|
||||||
|
if emitter.write_handler != nil {
|
||||||
|
panic("must set the output target only once")
|
||||||
|
}
|
||||||
|
emitter.write_handler = yaml_writer_write_handler
|
||||||
|
emitter.output_writer = w
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the output encoding.
|
||||||
|
func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
|
||||||
|
if emitter.encoding != yaml_ANY_ENCODING {
|
||||||
|
panic("must set the output encoding only once")
|
||||||
|
}
|
||||||
|
emitter.encoding = encoding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the canonical output style.
|
||||||
|
func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
|
||||||
|
emitter.canonical = canonical
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the indentation increment.
|
||||||
|
func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
|
||||||
|
if indent < 2 || indent > 9 {
|
||||||
|
indent = 2
|
||||||
|
}
|
||||||
|
emitter.best_indent = indent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the preferred line width.
|
||||||
|
func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
|
||||||
|
if width < 0 {
|
||||||
|
width = -1
|
||||||
|
}
|
||||||
|
emitter.best_width = width
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set if unescaped non-ASCII characters are allowed.
|
||||||
|
func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
|
||||||
|
emitter.unicode = unicode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the preferred line break character.
|
||||||
|
func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
|
||||||
|
emitter.line_break = line_break
|
||||||
|
}
|
||||||
|
|
||||||
|
///*
|
||||||
|
// * Destroy a token object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(void)
|
||||||
|
//yaml_token_delete(yaml_token_t *token)
|
||||||
|
//{
|
||||||
|
// assert(token); // Non-NULL token object expected.
|
||||||
|
//
|
||||||
|
// switch (token.type)
|
||||||
|
// {
|
||||||
|
// case YAML_TAG_DIRECTIVE_TOKEN:
|
||||||
|
// yaml_free(token.data.tag_directive.handle);
|
||||||
|
// yaml_free(token.data.tag_directive.prefix);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_ALIAS_TOKEN:
|
||||||
|
// yaml_free(token.data.alias.value);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_ANCHOR_TOKEN:
|
||||||
|
// yaml_free(token.data.anchor.value);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_TAG_TOKEN:
|
||||||
|
// yaml_free(token.data.tag.handle);
|
||||||
|
// yaml_free(token.data.tag.suffix);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_SCALAR_TOKEN:
|
||||||
|
// yaml_free(token.data.scalar.value);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// memset(token, 0, sizeof(yaml_token_t));
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Check if a string is a valid UTF-8 sequence.
|
||||||
|
// *
|
||||||
|
// * Check 'reader.c' for more details on UTF-8 encoding.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//static int
|
||||||
|
//yaml_check_utf8(yaml_char_t *start, size_t length)
|
||||||
|
//{
|
||||||
|
// yaml_char_t *end = start+length;
|
||||||
|
// yaml_char_t *pointer = start;
|
||||||
|
//
|
||||||
|
// while (pointer < end) {
|
||||||
|
// unsigned char octet;
|
||||||
|
// unsigned int width;
|
||||||
|
// unsigned int value;
|
||||||
|
// size_t k;
|
||||||
|
//
|
||||||
|
// octet = pointer[0];
|
||||||
|
// width = (octet & 0x80) == 0x00 ? 1 :
|
||||||
|
// (octet & 0xE0) == 0xC0 ? 2 :
|
||||||
|
// (octet & 0xF0) == 0xE0 ? 3 :
|
||||||
|
// (octet & 0xF8) == 0xF0 ? 4 : 0;
|
||||||
|
// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
|
||||||
|
// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
|
||||||
|
// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
|
||||||
|
// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
|
||||||
|
// if (!width) return 0;
|
||||||
|
// if (pointer+width > end) return 0;
|
||||||
|
// for (k = 1; k < width; k ++) {
|
||||||
|
// octet = pointer[k];
|
||||||
|
// if ((octet & 0xC0) != 0x80) return 0;
|
||||||
|
// value = (value << 6) + (octet & 0x3F);
|
||||||
|
// }
|
||||||
|
// if (!((width == 1) ||
|
||||||
|
// (width == 2 && value >= 0x80) ||
|
||||||
|
// (width == 3 && value >= 0x800) ||
|
||||||
|
// (width == 4 && value >= 0x10000))) return 0;
|
||||||
|
//
|
||||||
|
// pointer += width;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return 1;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Create STREAM-START.
|
||||||
|
func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_STREAM_START_EVENT,
|
||||||
|
encoding: encoding,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create STREAM-END.
|
||||||
|
func yaml_stream_end_event_initialize(event *yaml_event_t) {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_STREAM_END_EVENT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create DOCUMENT-START.
|
||||||
|
func yaml_document_start_event_initialize(
|
||||||
|
event *yaml_event_t,
|
||||||
|
version_directive *yaml_version_directive_t,
|
||||||
|
tag_directives []yaml_tag_directive_t,
|
||||||
|
implicit bool,
|
||||||
|
) {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_DOCUMENT_START_EVENT,
|
||||||
|
version_directive: version_directive,
|
||||||
|
tag_directives: tag_directives,
|
||||||
|
implicit: implicit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create DOCUMENT-END.
|
||||||
|
func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_DOCUMENT_END_EVENT,
|
||||||
|
implicit: implicit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create ALIAS.
|
||||||
|
func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_ALIAS_EVENT,
|
||||||
|
anchor: anchor,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SCALAR.
|
||||||
|
func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_SCALAR_EVENT,
|
||||||
|
anchor: anchor,
|
||||||
|
tag: tag,
|
||||||
|
value: value,
|
||||||
|
implicit: plain_implicit,
|
||||||
|
quoted_implicit: quoted_implicit,
|
||||||
|
style: yaml_style_t(style),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SEQUENCE-START.
|
||||||
|
func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_SEQUENCE_START_EVENT,
|
||||||
|
anchor: anchor,
|
||||||
|
tag: tag,
|
||||||
|
implicit: implicit,
|
||||||
|
style: yaml_style_t(style),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SEQUENCE-END.
|
||||||
|
func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_SEQUENCE_END_EVENT,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create MAPPING-START.
|
||||||
|
func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_MAPPING_START_EVENT,
|
||||||
|
anchor: anchor,
|
||||||
|
tag: tag,
|
||||||
|
implicit: implicit,
|
||||||
|
style: yaml_style_t(style),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create MAPPING-END.
|
||||||
|
func yaml_mapping_end_event_initialize(event *yaml_event_t) {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_MAPPING_END_EVENT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy an event object.
|
||||||
|
func yaml_event_delete(event *yaml_event_t) {
|
||||||
|
*event = yaml_event_t{}
|
||||||
|
}
|
||||||
|
|
||||||
|
///*
|
||||||
|
// * Create a document object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_initialize(document *yaml_document_t,
|
||||||
|
// version_directive *yaml_version_directive_t,
|
||||||
|
// tag_directives_start *yaml_tag_directive_t,
|
||||||
|
// tag_directives_end *yaml_tag_directive_t,
|
||||||
|
// start_implicit int, end_implicit int)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// struct {
|
||||||
|
// start *yaml_node_t
|
||||||
|
// end *yaml_node_t
|
||||||
|
// top *yaml_node_t
|
||||||
|
// } nodes = { NULL, NULL, NULL }
|
||||||
|
// version_directive_copy *yaml_version_directive_t = NULL
|
||||||
|
// struct {
|
||||||
|
// start *yaml_tag_directive_t
|
||||||
|
// end *yaml_tag_directive_t
|
||||||
|
// top *yaml_tag_directive_t
|
||||||
|
// } tag_directives_copy = { NULL, NULL, NULL }
|
||||||
|
// value yaml_tag_directive_t = { NULL, NULL }
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
// assert((tag_directives_start && tag_directives_end) ||
|
||||||
|
// (tag_directives_start == tag_directives_end))
|
||||||
|
// // Valid tag directives are expected.
|
||||||
|
//
|
||||||
|
// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
|
||||||
|
//
|
||||||
|
// if (version_directive) {
|
||||||
|
// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
|
||||||
|
// if (!version_directive_copy) goto error
|
||||||
|
// version_directive_copy.major = version_directive.major
|
||||||
|
// version_directive_copy.minor = version_directive.minor
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (tag_directives_start != tag_directives_end) {
|
||||||
|
// tag_directive *yaml_tag_directive_t
|
||||||
|
// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
|
||||||
|
// goto error
|
||||||
|
// for (tag_directive = tag_directives_start
|
||||||
|
// tag_directive != tag_directives_end; tag_directive ++) {
|
||||||
|
// assert(tag_directive.handle)
|
||||||
|
// assert(tag_directive.prefix)
|
||||||
|
// if (!yaml_check_utf8(tag_directive.handle,
|
||||||
|
// strlen((char *)tag_directive.handle)))
|
||||||
|
// goto error
|
||||||
|
// if (!yaml_check_utf8(tag_directive.prefix,
|
||||||
|
// strlen((char *)tag_directive.prefix)))
|
||||||
|
// goto error
|
||||||
|
// value.handle = yaml_strdup(tag_directive.handle)
|
||||||
|
// value.prefix = yaml_strdup(tag_directive.prefix)
|
||||||
|
// if (!value.handle || !value.prefix) goto error
|
||||||
|
// if (!PUSH(&context, tag_directives_copy, value))
|
||||||
|
// goto error
|
||||||
|
// value.handle = NULL
|
||||||
|
// value.prefix = NULL
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
|
||||||
|
// tag_directives_copy.start, tag_directives_copy.top,
|
||||||
|
// start_implicit, end_implicit, mark, mark)
|
||||||
|
//
|
||||||
|
// return 1
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// STACK_DEL(&context, nodes)
|
||||||
|
// yaml_free(version_directive_copy)
|
||||||
|
// while (!STACK_EMPTY(&context, tag_directives_copy)) {
|
||||||
|
// value yaml_tag_directive_t = POP(&context, tag_directives_copy)
|
||||||
|
// yaml_free(value.handle)
|
||||||
|
// yaml_free(value.prefix)
|
||||||
|
// }
|
||||||
|
// STACK_DEL(&context, tag_directives_copy)
|
||||||
|
// yaml_free(value.handle)
|
||||||
|
// yaml_free(value.prefix)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Destroy a document object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(void)
|
||||||
|
//yaml_document_delete(document *yaml_document_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// tag_directive *yaml_tag_directive_t
|
||||||
|
//
|
||||||
|
// context.error = YAML_NO_ERROR // Eliminate a compiler warning.
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// while (!STACK_EMPTY(&context, document.nodes)) {
|
||||||
|
// node yaml_node_t = POP(&context, document.nodes)
|
||||||
|
// yaml_free(node.tag)
|
||||||
|
// switch (node.type) {
|
||||||
|
// case YAML_SCALAR_NODE:
|
||||||
|
// yaml_free(node.data.scalar.value)
|
||||||
|
// break
|
||||||
|
// case YAML_SEQUENCE_NODE:
|
||||||
|
// STACK_DEL(&context, node.data.sequence.items)
|
||||||
|
// break
|
||||||
|
// case YAML_MAPPING_NODE:
|
||||||
|
// STACK_DEL(&context, node.data.mapping.pairs)
|
||||||
|
// break
|
||||||
|
// default:
|
||||||
|
// assert(0) // Should not happen.
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// STACK_DEL(&context, document.nodes)
|
||||||
|
//
|
||||||
|
// yaml_free(document.version_directive)
|
||||||
|
// for (tag_directive = document.tag_directives.start
|
||||||
|
// tag_directive != document.tag_directives.end
|
||||||
|
// tag_directive++) {
|
||||||
|
// yaml_free(tag_directive.handle)
|
||||||
|
// yaml_free(tag_directive.prefix)
|
||||||
|
// }
|
||||||
|
// yaml_free(document.tag_directives.start)
|
||||||
|
//
|
||||||
|
// memset(document, 0, sizeof(yaml_document_t))
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Get a document node.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(yaml_node_t *)
|
||||||
|
//yaml_document_get_node(document *yaml_document_t, index int)
|
||||||
|
//{
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
|
||||||
|
// return document.nodes.start + index - 1
|
||||||
|
// }
|
||||||
|
// return NULL
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Get the root object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(yaml_node_t *)
|
||||||
|
//yaml_document_get_root_node(document *yaml_document_t)
|
||||||
|
//{
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (document.nodes.top != document.nodes.start) {
|
||||||
|
// return document.nodes.start
|
||||||
|
// }
|
||||||
|
// return NULL
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Add a scalar node to a document.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_add_scalar(document *yaml_document_t,
|
||||||
|
// tag *yaml_char_t, value *yaml_char_t, length int,
|
||||||
|
// style yaml_scalar_style_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
// tag_copy *yaml_char_t = NULL
|
||||||
|
// value_copy *yaml_char_t = NULL
|
||||||
|
// node yaml_node_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
// assert(value) // Non-NULL value is expected.
|
||||||
|
//
|
||||||
|
// if (!tag) {
|
||||||
|
// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
||||||
|
// tag_copy = yaml_strdup(tag)
|
||||||
|
// if (!tag_copy) goto error
|
||||||
|
//
|
||||||
|
// if (length < 0) {
|
||||||
|
// length = strlen((char *)value)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(value, length)) goto error
|
||||||
|
// value_copy = yaml_malloc(length+1)
|
||||||
|
// if (!value_copy) goto error
|
||||||
|
// memcpy(value_copy, value, length)
|
||||||
|
// value_copy[length] = '\0'
|
||||||
|
//
|
||||||
|
// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
|
||||||
|
// if (!PUSH(&context, document.nodes, node)) goto error
|
||||||
|
//
|
||||||
|
// return document.nodes.top - document.nodes.start
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// yaml_free(tag_copy)
|
||||||
|
// yaml_free(value_copy)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Add a sequence node to a document.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_add_sequence(document *yaml_document_t,
|
||||||
|
// tag *yaml_char_t, style yaml_sequence_style_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
// tag_copy *yaml_char_t = NULL
|
||||||
|
// struct {
|
||||||
|
// start *yaml_node_item_t
|
||||||
|
// end *yaml_node_item_t
|
||||||
|
// top *yaml_node_item_t
|
||||||
|
// } items = { NULL, NULL, NULL }
|
||||||
|
// node yaml_node_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (!tag) {
|
||||||
|
// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
||||||
|
// tag_copy = yaml_strdup(tag)
|
||||||
|
// if (!tag_copy) goto error
|
||||||
|
//
|
||||||
|
// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
|
||||||
|
//
|
||||||
|
// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
|
||||||
|
// style, mark, mark)
|
||||||
|
// if (!PUSH(&context, document.nodes, node)) goto error
|
||||||
|
//
|
||||||
|
// return document.nodes.top - document.nodes.start
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// STACK_DEL(&context, items)
|
||||||
|
// yaml_free(tag_copy)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Add a mapping node to a document.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_add_mapping(document *yaml_document_t,
|
||||||
|
// tag *yaml_char_t, style yaml_mapping_style_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
// tag_copy *yaml_char_t = NULL
|
||||||
|
// struct {
|
||||||
|
// start *yaml_node_pair_t
|
||||||
|
// end *yaml_node_pair_t
|
||||||
|
// top *yaml_node_pair_t
|
||||||
|
// } pairs = { NULL, NULL, NULL }
|
||||||
|
// node yaml_node_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (!tag) {
|
||||||
|
// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
||||||
|
// tag_copy = yaml_strdup(tag)
|
||||||
|
// if (!tag_copy) goto error
|
||||||
|
//
|
||||||
|
// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
|
||||||
|
//
|
||||||
|
// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
|
||||||
|
// style, mark, mark)
|
||||||
|
// if (!PUSH(&context, document.nodes, node)) goto error
|
||||||
|
//
|
||||||
|
// return document.nodes.top - document.nodes.start
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// STACK_DEL(&context, pairs)
|
||||||
|
// yaml_free(tag_copy)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Append an item to a sequence node.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_append_sequence_item(document *yaml_document_t,
|
||||||
|
// sequence int, item int)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document is required.
|
||||||
|
// assert(sequence > 0
|
||||||
|
// && document.nodes.start + sequence <= document.nodes.top)
|
||||||
|
// // Valid sequence id is required.
|
||||||
|
// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
|
||||||
|
// // A sequence node is required.
|
||||||
|
// assert(item > 0 && document.nodes.start + item <= document.nodes.top)
|
||||||
|
// // Valid item id is required.
|
||||||
|
//
|
||||||
|
// if (!PUSH(&context,
|
||||||
|
// document.nodes.start[sequence-1].data.sequence.items, item))
|
||||||
|
// return 0
|
||||||
|
//
|
||||||
|
// return 1
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Append a pair of a key and a value to a mapping node.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_append_mapping_pair(document *yaml_document_t,
|
||||||
|
// mapping int, key int, value int)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
//
|
||||||
|
// pair yaml_node_pair_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document is required.
|
||||||
|
// assert(mapping > 0
|
||||||
|
// && document.nodes.start + mapping <= document.nodes.top)
|
||||||
|
// // Valid mapping id is required.
|
||||||
|
// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
|
||||||
|
// // A mapping node is required.
|
||||||
|
// assert(key > 0 && document.nodes.start + key <= document.nodes.top)
|
||||||
|
// // Valid key id is required.
|
||||||
|
// assert(value > 0 && document.nodes.start + value <= document.nodes.top)
|
||||||
|
// // Valid value id is required.
|
||||||
|
//
|
||||||
|
// pair.key = key
|
||||||
|
// pair.value = value
|
||||||
|
//
|
||||||
|
// if (!PUSH(&context,
|
||||||
|
// document.nodes.start[mapping-1].data.mapping.pairs, pair))
|
||||||
|
// return 0
|
||||||
|
//
|
||||||
|
// return 1
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
950
vendor/gopkg.in/yaml.v3/decode.go
generated
vendored
Normal file
950
vendor/gopkg.in/yaml.v3/decode.go
generated
vendored
Normal file
|
@ -0,0 +1,950 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Parser, produces a node tree out of a libyaml event stream.
|
||||||
|
|
||||||
|
type parser struct {
|
||||||
|
parser yaml_parser_t
|
||||||
|
event yaml_event_t
|
||||||
|
doc *Node
|
||||||
|
anchors map[string]*Node
|
||||||
|
doneInit bool
|
||||||
|
textless bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParser(b []byte) *parser {
|
||||||
|
p := parser{}
|
||||||
|
if !yaml_parser_initialize(&p.parser) {
|
||||||
|
panic("failed to initialize YAML emitter")
|
||||||
|
}
|
||||||
|
if len(b) == 0 {
|
||||||
|
b = []byte{'\n'}
|
||||||
|
}
|
||||||
|
yaml_parser_set_input_string(&p.parser, b)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParserFromReader(r io.Reader) *parser {
|
||||||
|
p := parser{}
|
||||||
|
if !yaml_parser_initialize(&p.parser) {
|
||||||
|
panic("failed to initialize YAML emitter")
|
||||||
|
}
|
||||||
|
yaml_parser_set_input_reader(&p.parser, r)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) init() {
|
||||||
|
if p.doneInit {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.anchors = make(map[string]*Node)
|
||||||
|
p.expect(yaml_STREAM_START_EVENT)
|
||||||
|
p.doneInit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) destroy() {
|
||||||
|
if p.event.typ != yaml_NO_EVENT {
|
||||||
|
yaml_event_delete(&p.event)
|
||||||
|
}
|
||||||
|
yaml_parser_delete(&p.parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect consumes an event from the event stream and
|
||||||
|
// checks that it's of the expected type.
|
||||||
|
func (p *parser) expect(e yaml_event_type_t) {
|
||||||
|
if p.event.typ == yaml_NO_EVENT {
|
||||||
|
if !yaml_parser_parse(&p.parser, &p.event) {
|
||||||
|
p.fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.event.typ == yaml_STREAM_END_EVENT {
|
||||||
|
failf("attempted to go past the end of stream; corrupted value?")
|
||||||
|
}
|
||||||
|
if p.event.typ != e {
|
||||||
|
p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
|
||||||
|
p.fail()
|
||||||
|
}
|
||||||
|
yaml_event_delete(&p.event)
|
||||||
|
p.event.typ = yaml_NO_EVENT
|
||||||
|
}
|
||||||
|
|
||||||
|
// peek peeks at the next event in the event stream,
|
||||||
|
// puts the results into p.event and returns the event type.
|
||||||
|
func (p *parser) peek() yaml_event_type_t {
|
||||||
|
if p.event.typ != yaml_NO_EVENT {
|
||||||
|
return p.event.typ
|
||||||
|
}
|
||||||
|
if !yaml_parser_parse(&p.parser, &p.event) {
|
||||||
|
p.fail()
|
||||||
|
}
|
||||||
|
return p.event.typ
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) fail() {
|
||||||
|
var where string
|
||||||
|
var line int
|
||||||
|
if p.parser.context_mark.line != 0 {
|
||||||
|
line = p.parser.context_mark.line
|
||||||
|
// Scanner errors don't iterate line before returning error
|
||||||
|
if p.parser.error == yaml_SCANNER_ERROR {
|
||||||
|
line++
|
||||||
|
}
|
||||||
|
} else if p.parser.problem_mark.line != 0 {
|
||||||
|
line = p.parser.problem_mark.line
|
||||||
|
// Scanner errors don't iterate line before returning error
|
||||||
|
if p.parser.error == yaml_SCANNER_ERROR {
|
||||||
|
line++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if line != 0 {
|
||||||
|
where = "line " + strconv.Itoa(line) + ": "
|
||||||
|
}
|
||||||
|
var msg string
|
||||||
|
if len(p.parser.problem) > 0 {
|
||||||
|
msg = p.parser.problem
|
||||||
|
} else {
|
||||||
|
msg = "unknown problem parsing YAML content"
|
||||||
|
}
|
||||||
|
failf("%s%s", where, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) anchor(n *Node, anchor []byte) {
|
||||||
|
if anchor != nil {
|
||||||
|
n.Anchor = string(anchor)
|
||||||
|
p.anchors[n.Anchor] = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) parse() *Node {
|
||||||
|
p.init()
|
||||||
|
switch p.peek() {
|
||||||
|
case yaml_SCALAR_EVENT:
|
||||||
|
return p.scalar()
|
||||||
|
case yaml_ALIAS_EVENT:
|
||||||
|
return p.alias()
|
||||||
|
case yaml_MAPPING_START_EVENT:
|
||||||
|
return p.mapping()
|
||||||
|
case yaml_SEQUENCE_START_EVENT:
|
||||||
|
return p.sequence()
|
||||||
|
case yaml_DOCUMENT_START_EVENT:
|
||||||
|
return p.document()
|
||||||
|
case yaml_STREAM_END_EVENT:
|
||||||
|
// Happens when attempting to decode an empty buffer.
|
||||||
|
return nil
|
||||||
|
case yaml_TAIL_COMMENT_EVENT:
|
||||||
|
panic("internal error: unexpected tail comment event (please report)")
|
||||||
|
default:
|
||||||
|
panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
|
||||||
|
var style Style
|
||||||
|
if tag != "" && tag != "!" {
|
||||||
|
tag = shortTag(tag)
|
||||||
|
style = TaggedStyle
|
||||||
|
} else if defaultTag != "" {
|
||||||
|
tag = defaultTag
|
||||||
|
} else if kind == ScalarNode {
|
||||||
|
tag, _ = resolve("", value)
|
||||||
|
}
|
||||||
|
n := &Node{
|
||||||
|
Kind: kind,
|
||||||
|
Tag: tag,
|
||||||
|
Value: value,
|
||||||
|
Style: style,
|
||||||
|
}
|
||||||
|
if !p.textless {
|
||||||
|
n.Line = p.event.start_mark.line + 1
|
||||||
|
n.Column = p.event.start_mark.column + 1
|
||||||
|
n.HeadComment = string(p.event.head_comment)
|
||||||
|
n.LineComment = string(p.event.line_comment)
|
||||||
|
n.FootComment = string(p.event.foot_comment)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) parseChild(parent *Node) *Node {
|
||||||
|
child := p.parse()
|
||||||
|
parent.Content = append(parent.Content, child)
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) document() *Node {
|
||||||
|
n := p.node(DocumentNode, "", "", "")
|
||||||
|
p.doc = n
|
||||||
|
p.expect(yaml_DOCUMENT_START_EVENT)
|
||||||
|
p.parseChild(n)
|
||||||
|
if p.peek() == yaml_DOCUMENT_END_EVENT {
|
||||||
|
n.FootComment = string(p.event.foot_comment)
|
||||||
|
}
|
||||||
|
p.expect(yaml_DOCUMENT_END_EVENT)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) alias() *Node {
|
||||||
|
n := p.node(AliasNode, "", "", string(p.event.anchor))
|
||||||
|
n.Alias = p.anchors[n.Value]
|
||||||
|
if n.Alias == nil {
|
||||||
|
failf("unknown anchor '%s' referenced", n.Value)
|
||||||
|
}
|
||||||
|
p.expect(yaml_ALIAS_EVENT)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) scalar() *Node {
|
||||||
|
var parsedStyle = p.event.scalar_style()
|
||||||
|
var nodeStyle Style
|
||||||
|
switch {
|
||||||
|
case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
|
||||||
|
nodeStyle = DoubleQuotedStyle
|
||||||
|
case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
|
||||||
|
nodeStyle = SingleQuotedStyle
|
||||||
|
case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
|
||||||
|
nodeStyle = LiteralStyle
|
||||||
|
case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
|
||||||
|
nodeStyle = FoldedStyle
|
||||||
|
}
|
||||||
|
var nodeValue = string(p.event.value)
|
||||||
|
var nodeTag = string(p.event.tag)
|
||||||
|
var defaultTag string
|
||||||
|
if nodeStyle == 0 {
|
||||||
|
if nodeValue == "<<" {
|
||||||
|
defaultTag = mergeTag
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
defaultTag = strTag
|
||||||
|
}
|
||||||
|
n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
|
||||||
|
n.Style |= nodeStyle
|
||||||
|
p.anchor(n, p.event.anchor)
|
||||||
|
p.expect(yaml_SCALAR_EVENT)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) sequence() *Node {
|
||||||
|
n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
|
||||||
|
if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
|
||||||
|
n.Style |= FlowStyle
|
||||||
|
}
|
||||||
|
p.anchor(n, p.event.anchor)
|
||||||
|
p.expect(yaml_SEQUENCE_START_EVENT)
|
||||||
|
for p.peek() != yaml_SEQUENCE_END_EVENT {
|
||||||
|
p.parseChild(n)
|
||||||
|
}
|
||||||
|
n.LineComment = string(p.event.line_comment)
|
||||||
|
n.FootComment = string(p.event.foot_comment)
|
||||||
|
p.expect(yaml_SEQUENCE_END_EVENT)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) mapping() *Node {
|
||||||
|
n := p.node(MappingNode, mapTag, string(p.event.tag), "")
|
||||||
|
block := true
|
||||||
|
if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
|
||||||
|
block = false
|
||||||
|
n.Style |= FlowStyle
|
||||||
|
}
|
||||||
|
p.anchor(n, p.event.anchor)
|
||||||
|
p.expect(yaml_MAPPING_START_EVENT)
|
||||||
|
for p.peek() != yaml_MAPPING_END_EVENT {
|
||||||
|
k := p.parseChild(n)
|
||||||
|
if block && k.FootComment != "" {
|
||||||
|
// Must be a foot comment for the prior value when being dedented.
|
||||||
|
if len(n.Content) > 2 {
|
||||||
|
n.Content[len(n.Content)-3].FootComment = k.FootComment
|
||||||
|
k.FootComment = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v := p.parseChild(n)
|
||||||
|
if k.FootComment == "" && v.FootComment != "" {
|
||||||
|
k.FootComment = v.FootComment
|
||||||
|
v.FootComment = ""
|
||||||
|
}
|
||||||
|
if p.peek() == yaml_TAIL_COMMENT_EVENT {
|
||||||
|
if k.FootComment == "" {
|
||||||
|
k.FootComment = string(p.event.foot_comment)
|
||||||
|
}
|
||||||
|
p.expect(yaml_TAIL_COMMENT_EVENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.LineComment = string(p.event.line_comment)
|
||||||
|
n.FootComment = string(p.event.foot_comment)
|
||||||
|
if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
|
||||||
|
n.Content[len(n.Content)-2].FootComment = n.FootComment
|
||||||
|
n.FootComment = ""
|
||||||
|
}
|
||||||
|
p.expect(yaml_MAPPING_END_EVENT)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Decoder, unmarshals a node into a provided value.
|
||||||
|
|
||||||
|
type decoder struct {
|
||||||
|
doc *Node
|
||||||
|
aliases map[*Node]bool
|
||||||
|
terrors []string
|
||||||
|
|
||||||
|
stringMapType reflect.Type
|
||||||
|
generalMapType reflect.Type
|
||||||
|
|
||||||
|
knownFields bool
|
||||||
|
uniqueKeys bool
|
||||||
|
decodeCount int
|
||||||
|
aliasCount int
|
||||||
|
aliasDepth int
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nodeType = reflect.TypeOf(Node{})
|
||||||
|
durationType = reflect.TypeOf(time.Duration(0))
|
||||||
|
stringMapType = reflect.TypeOf(map[string]interface{}{})
|
||||||
|
generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
|
||||||
|
ifaceType = generalMapType.Elem()
|
||||||
|
timeType = reflect.TypeOf(time.Time{})
|
||||||
|
ptrTimeType = reflect.TypeOf(&time.Time{})
|
||||||
|
)
|
||||||
|
|
||||||
|
func newDecoder() *decoder {
|
||||||
|
d := &decoder{
|
||||||
|
stringMapType: stringMapType,
|
||||||
|
generalMapType: generalMapType,
|
||||||
|
uniqueKeys: true,
|
||||||
|
}
|
||||||
|
d.aliases = make(map[*Node]bool)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
|
||||||
|
if n.Tag != "" {
|
||||||
|
tag = n.Tag
|
||||||
|
}
|
||||||
|
value := n.Value
|
||||||
|
if tag != seqTag && tag != mapTag {
|
||||||
|
if len(value) > 10 {
|
||||||
|
value = " `" + value[:7] + "...`"
|
||||||
|
} else {
|
||||||
|
value = " `" + value + "`"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
|
||||||
|
err := u.UnmarshalYAML(n)
|
||||||
|
if e, ok := err.(*TypeError); ok {
|
||||||
|
d.terrors = append(d.terrors, e.Errors...)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
|
||||||
|
terrlen := len(d.terrors)
|
||||||
|
err := u.UnmarshalYAML(func(v interface{}) (err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
d.unmarshal(n, reflect.ValueOf(v))
|
||||||
|
if len(d.terrors) > terrlen {
|
||||||
|
issues := d.terrors[terrlen:]
|
||||||
|
d.terrors = d.terrors[:terrlen]
|
||||||
|
return &TypeError{issues}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if e, ok := err.(*TypeError); ok {
|
||||||
|
d.terrors = append(d.terrors, e.Errors...)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
|
||||||
|
// if a value is found to implement it.
|
||||||
|
// It returns the initialized and dereferenced out value, whether
|
||||||
|
// unmarshalling was already done by UnmarshalYAML, and if so whether
|
||||||
|
// its types unmarshalled appropriately.
|
||||||
|
//
|
||||||
|
// If n holds a null value, prepare returns before doing anything.
|
||||||
|
func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
|
||||||
|
if n.ShortTag() == nullTag {
|
||||||
|
return out, false, false
|
||||||
|
}
|
||||||
|
again := true
|
||||||
|
for again {
|
||||||
|
again = false
|
||||||
|
if out.Kind() == reflect.Ptr {
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.New(out.Type().Elem()))
|
||||||
|
}
|
||||||
|
out = out.Elem()
|
||||||
|
again = true
|
||||||
|
}
|
||||||
|
if out.CanAddr() {
|
||||||
|
outi := out.Addr().Interface()
|
||||||
|
if u, ok := outi.(Unmarshaler); ok {
|
||||||
|
good = d.callUnmarshaler(n, u)
|
||||||
|
return out, true, good
|
||||||
|
}
|
||||||
|
if u, ok := outi.(obsoleteUnmarshaler); ok {
|
||||||
|
good = d.callObsoleteUnmarshaler(n, u)
|
||||||
|
return out, true, good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
|
||||||
|
if n.ShortTag() == nullTag {
|
||||||
|
return reflect.Value{}
|
||||||
|
}
|
||||||
|
for _, num := range index {
|
||||||
|
for {
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
if v.IsNil() {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v = v.Field(num)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 400,000 decode operations is ~500kb of dense object declarations, or
|
||||||
|
// ~5kb of dense object declarations with 10000% alias expansion
|
||||||
|
alias_ratio_range_low = 400000
|
||||||
|
|
||||||
|
// 4,000,000 decode operations is ~5MB of dense object declarations, or
|
||||||
|
// ~4.5MB of dense object declarations with 10% alias expansion
|
||||||
|
alias_ratio_range_high = 4000000
|
||||||
|
|
||||||
|
// alias_ratio_range is the range over which we scale allowed alias ratios
|
||||||
|
alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
|
||||||
|
)
|
||||||
|
|
||||||
|
func allowedAliasRatio(decodeCount int) float64 {
|
||||||
|
switch {
|
||||||
|
case decodeCount <= alias_ratio_range_low:
|
||||||
|
// allow 99% to come from alias expansion for small-to-medium documents
|
||||||
|
return 0.99
|
||||||
|
case decodeCount >= alias_ratio_range_high:
|
||||||
|
// allow 10% to come from alias expansion for very large documents
|
||||||
|
return 0.10
|
||||||
|
default:
|
||||||
|
// scale smoothly from 99% down to 10% over the range.
|
||||||
|
// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
|
||||||
|
// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
|
||||||
|
return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
|
||||||
|
d.decodeCount++
|
||||||
|
if d.aliasDepth > 0 {
|
||||||
|
d.aliasCount++
|
||||||
|
}
|
||||||
|
if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
|
||||||
|
failf("document contains excessive aliasing")
|
||||||
|
}
|
||||||
|
if out.Type() == nodeType {
|
||||||
|
out.Set(reflect.ValueOf(n).Elem())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch n.Kind {
|
||||||
|
case DocumentNode:
|
||||||
|
return d.document(n, out)
|
||||||
|
case AliasNode:
|
||||||
|
return d.alias(n, out)
|
||||||
|
}
|
||||||
|
out, unmarshaled, good := d.prepare(n, out)
|
||||||
|
if unmarshaled {
|
||||||
|
return good
|
||||||
|
}
|
||||||
|
switch n.Kind {
|
||||||
|
case ScalarNode:
|
||||||
|
good = d.scalar(n, out)
|
||||||
|
case MappingNode:
|
||||||
|
good = d.mapping(n, out)
|
||||||
|
case SequenceNode:
|
||||||
|
good = d.sequence(n, out)
|
||||||
|
case 0:
|
||||||
|
if n.IsZero() {
|
||||||
|
return d.null(out)
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
failf("cannot decode node with unknown kind %d", n.Kind)
|
||||||
|
}
|
||||||
|
return good
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
|
||||||
|
if len(n.Content) == 1 {
|
||||||
|
d.doc = n
|
||||||
|
d.unmarshal(n.Content[0], out)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
|
||||||
|
if d.aliases[n] {
|
||||||
|
// TODO this could actually be allowed in some circumstances.
|
||||||
|
failf("anchor '%s' value contains itself", n.Value)
|
||||||
|
}
|
||||||
|
d.aliases[n] = true
|
||||||
|
d.aliasDepth++
|
||||||
|
good = d.unmarshal(n.Alias, out)
|
||||||
|
d.aliasDepth--
|
||||||
|
delete(d.aliases, n)
|
||||||
|
return good
|
||||||
|
}
|
||||||
|
|
||||||
|
var zeroValue reflect.Value
|
||||||
|
|
||||||
|
func resetMap(out reflect.Value) {
|
||||||
|
for _, k := range out.MapKeys() {
|
||||||
|
out.SetMapIndex(k, zeroValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) null(out reflect.Value) bool {
|
||||||
|
if out.CanAddr() {
|
||||||
|
switch out.Kind() {
|
||||||
|
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
|
||||||
|
out.Set(reflect.Zero(out.Type()))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) scalar(n *Node, out reflect.Value) bool {
|
||||||
|
var tag string
|
||||||
|
var resolved interface{}
|
||||||
|
if n.indicatedString() {
|
||||||
|
tag = strTag
|
||||||
|
resolved = n.Value
|
||||||
|
} else {
|
||||||
|
tag, resolved = resolve(n.Tag, n.Value)
|
||||||
|
if tag == binaryTag {
|
||||||
|
data, err := base64.StdEncoding.DecodeString(resolved.(string))
|
||||||
|
if err != nil {
|
||||||
|
failf("!!binary value contains invalid base64 data")
|
||||||
|
}
|
||||||
|
resolved = string(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resolved == nil {
|
||||||
|
return d.null(out)
|
||||||
|
}
|
||||||
|
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
|
||||||
|
// We've resolved to exactly the type we want, so use that.
|
||||||
|
out.Set(resolvedv)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Perhaps we can use the value as a TextUnmarshaler to
|
||||||
|
// set its value.
|
||||||
|
if out.CanAddr() {
|
||||||
|
u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
|
||||||
|
if ok {
|
||||||
|
var text []byte
|
||||||
|
if tag == binaryTag {
|
||||||
|
text = []byte(resolved.(string))
|
||||||
|
} else {
|
||||||
|
// We let any value be unmarshaled into TextUnmarshaler.
|
||||||
|
// That might be more lax than we'd like, but the
|
||||||
|
// TextUnmarshaler itself should bowl out any dubious values.
|
||||||
|
text = []byte(n.Value)
|
||||||
|
}
|
||||||
|
err := u.UnmarshalText(text)
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch out.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
if tag == binaryTag {
|
||||||
|
out.SetString(resolved.(string))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
out.SetString(n.Value)
|
||||||
|
return true
|
||||||
|
case reflect.Interface:
|
||||||
|
out.Set(reflect.ValueOf(resolved))
|
||||||
|
return true
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
// This used to work in v2, but it's very unfriendly.
|
||||||
|
isDuration := out.Type() == durationType
|
||||||
|
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case int:
|
||||||
|
if !isDuration && !out.OverflowInt(int64(resolved)) {
|
||||||
|
out.SetInt(int64(resolved))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
if !isDuration && !out.OverflowInt(resolved) {
|
||||||
|
out.SetInt(resolved)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case uint64:
|
||||||
|
if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
||||||
|
out.SetInt(int64(resolved))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
||||||
|
out.SetInt(int64(resolved))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
if out.Type() == durationType {
|
||||||
|
d, err := time.ParseDuration(resolved)
|
||||||
|
if err == nil {
|
||||||
|
out.SetInt(int64(d))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case int:
|
||||||
|
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case uint64:
|
||||||
|
if !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Bool:
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case bool:
|
||||||
|
out.SetBool(resolved)
|
||||||
|
return true
|
||||||
|
case string:
|
||||||
|
// This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
|
||||||
|
// It only works if explicitly attempting to unmarshal into a typed bool value.
|
||||||
|
switch resolved {
|
||||||
|
case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
|
||||||
|
out.SetBool(true)
|
||||||
|
return true
|
||||||
|
case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
|
||||||
|
out.SetBool(false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case int:
|
||||||
|
out.SetFloat(float64(resolved))
|
||||||
|
return true
|
||||||
|
case int64:
|
||||||
|
out.SetFloat(float64(resolved))
|
||||||
|
return true
|
||||||
|
case uint64:
|
||||||
|
out.SetFloat(float64(resolved))
|
||||||
|
return true
|
||||||
|
case float64:
|
||||||
|
out.SetFloat(resolved)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
|
||||||
|
out.Set(resolvedv)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case reflect.Ptr:
|
||||||
|
panic("yaml internal error: please report the issue")
|
||||||
|
}
|
||||||
|
d.terror(n, tag, out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func settableValueOf(i interface{}) reflect.Value {
|
||||||
|
v := reflect.ValueOf(i)
|
||||||
|
sv := reflect.New(v.Type()).Elem()
|
||||||
|
sv.Set(v)
|
||||||
|
return sv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
|
||||||
|
l := len(n.Content)
|
||||||
|
|
||||||
|
var iface reflect.Value
|
||||||
|
switch out.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
out.Set(reflect.MakeSlice(out.Type(), l, l))
|
||||||
|
case reflect.Array:
|
||||||
|
if l != out.Len() {
|
||||||
|
failf("invalid array: want %d elements but got %d", out.Len(), l)
|
||||||
|
}
|
||||||
|
case reflect.Interface:
|
||||||
|
// No type hints. Will have to use a generic sequence.
|
||||||
|
iface = out
|
||||||
|
out = settableValueOf(make([]interface{}, l))
|
||||||
|
default:
|
||||||
|
d.terror(n, seqTag, out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
et := out.Type().Elem()
|
||||||
|
|
||||||
|
j := 0
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
e := reflect.New(et).Elem()
|
||||||
|
if ok := d.unmarshal(n.Content[i], e); ok {
|
||||||
|
out.Index(j).Set(e)
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if out.Kind() != reflect.Array {
|
||||||
|
out.Set(out.Slice(0, j))
|
||||||
|
}
|
||||||
|
if iface.IsValid() {
|
||||||
|
iface.Set(out)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
|
||||||
|
l := len(n.Content)
|
||||||
|
if d.uniqueKeys {
|
||||||
|
nerrs := len(d.terrors)
|
||||||
|
for i := 0; i < l; i += 2 {
|
||||||
|
ni := n.Content[i]
|
||||||
|
for j := i + 2; j < l; j += 2 {
|
||||||
|
nj := n.Content[j]
|
||||||
|
if ni.Kind == nj.Kind && ni.Value == nj.Value {
|
||||||
|
d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(d.terrors) > nerrs {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch out.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
return d.mappingStruct(n, out)
|
||||||
|
case reflect.Map:
|
||||||
|
// okay
|
||||||
|
case reflect.Interface:
|
||||||
|
iface := out
|
||||||
|
if isStringMap(n) {
|
||||||
|
out = reflect.MakeMap(d.stringMapType)
|
||||||
|
} else {
|
||||||
|
out = reflect.MakeMap(d.generalMapType)
|
||||||
|
}
|
||||||
|
iface.Set(out)
|
||||||
|
default:
|
||||||
|
d.terror(n, mapTag, out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
outt := out.Type()
|
||||||
|
kt := outt.Key()
|
||||||
|
et := outt.Elem()
|
||||||
|
|
||||||
|
stringMapType := d.stringMapType
|
||||||
|
generalMapType := d.generalMapType
|
||||||
|
if outt.Elem() == ifaceType {
|
||||||
|
if outt.Key().Kind() == reflect.String {
|
||||||
|
d.stringMapType = outt
|
||||||
|
} else if outt.Key() == ifaceType {
|
||||||
|
d.generalMapType = outt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapIsNew := false
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.MakeMap(outt))
|
||||||
|
mapIsNew = true
|
||||||
|
}
|
||||||
|
for i := 0; i < l; i += 2 {
|
||||||
|
if isMerge(n.Content[i]) {
|
||||||
|
d.merge(n.Content[i+1], out)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k := reflect.New(kt).Elem()
|
||||||
|
if d.unmarshal(n.Content[i], k) {
|
||||||
|
kkind := k.Kind()
|
||||||
|
if kkind == reflect.Interface {
|
||||||
|
kkind = k.Elem().Kind()
|
||||||
|
}
|
||||||
|
if kkind == reflect.Map || kkind == reflect.Slice {
|
||||||
|
failf("invalid map key: %#v", k.Interface())
|
||||||
|
}
|
||||||
|
e := reflect.New(et).Elem()
|
||||||
|
if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) {
|
||||||
|
out.SetMapIndex(k, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.stringMapType = stringMapType
|
||||||
|
d.generalMapType = generalMapType
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStringMap(n *Node) bool {
|
||||||
|
if n.Kind != MappingNode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
l := len(n.Content)
|
||||||
|
for i := 0; i < l; i += 2 {
|
||||||
|
if n.Content[i].ShortTag() != strTag {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
|
||||||
|
sinfo, err := getStructInfo(out.Type())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var inlineMap reflect.Value
|
||||||
|
var elemType reflect.Type
|
||||||
|
if sinfo.InlineMap != -1 {
|
||||||
|
inlineMap = out.Field(sinfo.InlineMap)
|
||||||
|
inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
|
||||||
|
elemType = inlineMap.Type().Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, index := range sinfo.InlineUnmarshalers {
|
||||||
|
field := d.fieldByIndex(n, out, index)
|
||||||
|
d.prepare(n, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
var doneFields []bool
|
||||||
|
if d.uniqueKeys {
|
||||||
|
doneFields = make([]bool, len(sinfo.FieldsList))
|
||||||
|
}
|
||||||
|
name := settableValueOf("")
|
||||||
|
l := len(n.Content)
|
||||||
|
for i := 0; i < l; i += 2 {
|
||||||
|
ni := n.Content[i]
|
||||||
|
if isMerge(ni) {
|
||||||
|
d.merge(n.Content[i+1], out)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !d.unmarshal(ni, name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info, ok := sinfo.FieldsMap[name.String()]; ok {
|
||||||
|
if d.uniqueKeys {
|
||||||
|
if doneFields[info.Id] {
|
||||||
|
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
doneFields[info.Id] = true
|
||||||
|
}
|
||||||
|
var field reflect.Value
|
||||||
|
if info.Inline == nil {
|
||||||
|
field = out.Field(info.Num)
|
||||||
|
} else {
|
||||||
|
field = d.fieldByIndex(n, out, info.Inline)
|
||||||
|
}
|
||||||
|
d.unmarshal(n.Content[i+1], field)
|
||||||
|
} else if sinfo.InlineMap != -1 {
|
||||||
|
if inlineMap.IsNil() {
|
||||||
|
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
|
||||||
|
}
|
||||||
|
value := reflect.New(elemType).Elem()
|
||||||
|
d.unmarshal(n.Content[i+1], value)
|
||||||
|
inlineMap.SetMapIndex(name, value)
|
||||||
|
} else if d.knownFields {
|
||||||
|
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func failWantMap() {
|
||||||
|
failf("map merge requires map or sequence of maps as the value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) merge(n *Node, out reflect.Value) {
|
||||||
|
switch n.Kind {
|
||||||
|
case MappingNode:
|
||||||
|
d.unmarshal(n, out)
|
||||||
|
case AliasNode:
|
||||||
|
if n.Alias != nil && n.Alias.Kind != MappingNode {
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
d.unmarshal(n, out)
|
||||||
|
case SequenceNode:
|
||||||
|
// Step backwards as earlier nodes take precedence.
|
||||||
|
for i := len(n.Content) - 1; i >= 0; i-- {
|
||||||
|
ni := n.Content[i]
|
||||||
|
if ni.Kind == AliasNode {
|
||||||
|
if ni.Alias != nil && ni.Alias.Kind != MappingNode {
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
} else if ni.Kind != MappingNode {
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
d.unmarshal(ni, out)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMerge(n *Node) bool {
|
||||||
|
return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
|
||||||
|
}
|
2020
vendor/gopkg.in/yaml.v3/emitterc.go
generated
vendored
Normal file
2020
vendor/gopkg.in/yaml.v3/emitterc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
577
vendor/gopkg.in/yaml.v3/encode.go
generated
vendored
Normal file
577
vendor/gopkg.in/yaml.v3/encode.go
generated
vendored
Normal file
|
@ -0,0 +1,577 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type encoder struct {
|
||||||
|
emitter yaml_emitter_t
|
||||||
|
event yaml_event_t
|
||||||
|
out []byte
|
||||||
|
flow bool
|
||||||
|
indent int
|
||||||
|
doneInit bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEncoder() *encoder {
|
||||||
|
e := &encoder{}
|
||||||
|
yaml_emitter_initialize(&e.emitter)
|
||||||
|
yaml_emitter_set_output_string(&e.emitter, &e.out)
|
||||||
|
yaml_emitter_set_unicode(&e.emitter, true)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEncoderWithWriter(w io.Writer) *encoder {
|
||||||
|
e := &encoder{}
|
||||||
|
yaml_emitter_initialize(&e.emitter)
|
||||||
|
yaml_emitter_set_output_writer(&e.emitter, w)
|
||||||
|
yaml_emitter_set_unicode(&e.emitter, true)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) init() {
|
||||||
|
if e.doneInit {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if e.indent == 0 {
|
||||||
|
e.indent = 4
|
||||||
|
}
|
||||||
|
e.emitter.best_indent = e.indent
|
||||||
|
yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
|
||||||
|
e.emit()
|
||||||
|
e.doneInit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) finish() {
|
||||||
|
e.emitter.open_ended = false
|
||||||
|
yaml_stream_end_event_initialize(&e.event)
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) destroy() {
|
||||||
|
yaml_emitter_delete(&e.emitter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) emit() {
|
||||||
|
// This will internally delete the e.event value.
|
||||||
|
e.must(yaml_emitter_emit(&e.emitter, &e.event))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) must(ok bool) {
|
||||||
|
if !ok {
|
||||||
|
msg := e.emitter.problem
|
||||||
|
if msg == "" {
|
||||||
|
msg = "unknown problem generating YAML content"
|
||||||
|
}
|
||||||
|
failf("%s", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) marshalDoc(tag string, in reflect.Value) {
|
||||||
|
e.init()
|
||||||
|
var node *Node
|
||||||
|
if in.IsValid() {
|
||||||
|
node, _ = in.Interface().(*Node)
|
||||||
|
}
|
||||||
|
if node != nil && node.Kind == DocumentNode {
|
||||||
|
e.nodev(in)
|
||||||
|
} else {
|
||||||
|
yaml_document_start_event_initialize(&e.event, nil, nil, true)
|
||||||
|
e.emit()
|
||||||
|
e.marshal(tag, in)
|
||||||
|
yaml_document_end_event_initialize(&e.event, true)
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) marshal(tag string, in reflect.Value) {
|
||||||
|
tag = shortTag(tag)
|
||||||
|
if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
|
||||||
|
e.nilv()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
iface := in.Interface()
|
||||||
|
switch value := iface.(type) {
|
||||||
|
case *Node:
|
||||||
|
e.nodev(in)
|
||||||
|
return
|
||||||
|
case Node:
|
||||||
|
if !in.CanAddr() {
|
||||||
|
var n = reflect.New(in.Type()).Elem()
|
||||||
|
n.Set(in)
|
||||||
|
in = n
|
||||||
|
}
|
||||||
|
e.nodev(in.Addr())
|
||||||
|
return
|
||||||
|
case time.Time:
|
||||||
|
e.timev(tag, in)
|
||||||
|
return
|
||||||
|
case *time.Time:
|
||||||
|
e.timev(tag, in.Elem())
|
||||||
|
return
|
||||||
|
case time.Duration:
|
||||||
|
e.stringv(tag, reflect.ValueOf(value.String()))
|
||||||
|
return
|
||||||
|
case Marshaler:
|
||||||
|
v, err := value.MarshalYAML()
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
if v == nil {
|
||||||
|
e.nilv()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.marshal(tag, reflect.ValueOf(v))
|
||||||
|
return
|
||||||
|
case encoding.TextMarshaler:
|
||||||
|
text, err := value.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
in = reflect.ValueOf(string(text))
|
||||||
|
case nil:
|
||||||
|
e.nilv()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch in.Kind() {
|
||||||
|
case reflect.Interface:
|
||||||
|
e.marshal(tag, in.Elem())
|
||||||
|
case reflect.Map:
|
||||||
|
e.mapv(tag, in)
|
||||||
|
case reflect.Ptr:
|
||||||
|
e.marshal(tag, in.Elem())
|
||||||
|
case reflect.Struct:
|
||||||
|
e.structv(tag, in)
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
e.slicev(tag, in)
|
||||||
|
case reflect.String:
|
||||||
|
e.stringv(tag, in)
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
e.intv(tag, in)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
e.uintv(tag, in)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
e.floatv(tag, in)
|
||||||
|
case reflect.Bool:
|
||||||
|
e.boolv(tag, in)
|
||||||
|
default:
|
||||||
|
panic("cannot marshal type: " + in.Type().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) mapv(tag string, in reflect.Value) {
|
||||||
|
e.mappingv(tag, func() {
|
||||||
|
keys := keyList(in.MapKeys())
|
||||||
|
sort.Sort(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
e.marshal("", k)
|
||||||
|
e.marshal("", in.MapIndex(k))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) {
|
||||||
|
for _, num := range index {
|
||||||
|
for {
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
if v.IsNil() {
|
||||||
|
return reflect.Value{}
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v = v.Field(num)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) structv(tag string, in reflect.Value) {
|
||||||
|
sinfo, err := getStructInfo(in.Type())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
e.mappingv(tag, func() {
|
||||||
|
for _, info := range sinfo.FieldsList {
|
||||||
|
var value reflect.Value
|
||||||
|
if info.Inline == nil {
|
||||||
|
value = in.Field(info.Num)
|
||||||
|
} else {
|
||||||
|
value = e.fieldByIndex(in, info.Inline)
|
||||||
|
if !value.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if info.OmitEmpty && isZero(value) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
e.marshal("", reflect.ValueOf(info.Key))
|
||||||
|
e.flow = info.Flow
|
||||||
|
e.marshal("", value)
|
||||||
|
}
|
||||||
|
if sinfo.InlineMap >= 0 {
|
||||||
|
m := in.Field(sinfo.InlineMap)
|
||||||
|
if m.Len() > 0 {
|
||||||
|
e.flow = false
|
||||||
|
keys := keyList(m.MapKeys())
|
||||||
|
sort.Sort(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
if _, found := sinfo.FieldsMap[k.String()]; found {
|
||||||
|
panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String()))
|
||||||
|
}
|
||||||
|
e.marshal("", k)
|
||||||
|
e.flow = false
|
||||||
|
e.marshal("", m.MapIndex(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) mappingv(tag string, f func()) {
|
||||||
|
implicit := tag == ""
|
||||||
|
style := yaml_BLOCK_MAPPING_STYLE
|
||||||
|
if e.flow {
|
||||||
|
e.flow = false
|
||||||
|
style = yaml_FLOW_MAPPING_STYLE
|
||||||
|
}
|
||||||
|
yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
|
||||||
|
e.emit()
|
||||||
|
f()
|
||||||
|
yaml_mapping_end_event_initialize(&e.event)
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) slicev(tag string, in reflect.Value) {
|
||||||
|
implicit := tag == ""
|
||||||
|
style := yaml_BLOCK_SEQUENCE_STYLE
|
||||||
|
if e.flow {
|
||||||
|
e.flow = false
|
||||||
|
style = yaml_FLOW_SEQUENCE_STYLE
|
||||||
|
}
|
||||||
|
e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
|
||||||
|
e.emit()
|
||||||
|
n := in.Len()
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
e.marshal("", in.Index(i))
|
||||||
|
}
|
||||||
|
e.must(yaml_sequence_end_event_initialize(&e.event))
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
|
||||||
|
//
|
||||||
|
// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
|
||||||
|
// in YAML 1.2 and by this package, but these should be marshalled quoted for
|
||||||
|
// the time being for compatibility with other parsers.
|
||||||
|
func isBase60Float(s string) (result bool) {
|
||||||
|
// Fast path.
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c := s[0]
|
||||||
|
if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Do the full match.
|
||||||
|
return base60float.MatchString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// From http://yaml.org/type/float.html, except the regular expression there
|
||||||
|
// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
|
||||||
|
var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
|
||||||
|
|
||||||
|
// isOldBool returns whether s is bool notation as defined in YAML 1.1.
|
||||||
|
//
|
||||||
|
// We continue to force strings that YAML 1.1 would interpret as booleans to be
|
||||||
|
// rendered as quotes strings so that the marshalled output valid for YAML 1.1
|
||||||
|
// parsing.
|
||||||
|
func isOldBool(s string) (result bool) {
|
||||||
|
switch s {
|
||||||
|
case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON",
|
||||||
|
"n", "N", "no", "No", "NO", "off", "Off", "OFF":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) stringv(tag string, in reflect.Value) {
|
||||||
|
var style yaml_scalar_style_t
|
||||||
|
s := in.String()
|
||||||
|
canUsePlain := true
|
||||||
|
switch {
|
||||||
|
case !utf8.ValidString(s):
|
||||||
|
if tag == binaryTag {
|
||||||
|
failf("explicitly tagged !!binary data must be base64-encoded")
|
||||||
|
}
|
||||||
|
if tag != "" {
|
||||||
|
failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
|
||||||
|
}
|
||||||
|
// It can't be encoded directly as YAML so use a binary tag
|
||||||
|
// and encode it as base64.
|
||||||
|
tag = binaryTag
|
||||||
|
s = encodeBase64(s)
|
||||||
|
case tag == "":
|
||||||
|
// Check to see if it would resolve to a specific
|
||||||
|
// tag when encoded unquoted. If it doesn't,
|
||||||
|
// there's no need to quote it.
|
||||||
|
rtag, _ := resolve("", s)
|
||||||
|
canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s))
|
||||||
|
}
|
||||||
|
// Note: it's possible for user code to emit invalid YAML
|
||||||
|
// if they explicitly specify a tag and a string containing
|
||||||
|
// text that's incompatible with that tag.
|
||||||
|
switch {
|
||||||
|
case strings.Contains(s, "\n"):
|
||||||
|
if e.flow {
|
||||||
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
||||||
|
} else {
|
||||||
|
style = yaml_LITERAL_SCALAR_STYLE
|
||||||
|
}
|
||||||
|
case canUsePlain:
|
||||||
|
style = yaml_PLAIN_SCALAR_STYLE
|
||||||
|
default:
|
||||||
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
||||||
|
}
|
||||||
|
e.emitScalar(s, "", tag, style, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) boolv(tag string, in reflect.Value) {
|
||||||
|
var s string
|
||||||
|
if in.Bool() {
|
||||||
|
s = "true"
|
||||||
|
} else {
|
||||||
|
s = "false"
|
||||||
|
}
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) intv(tag string, in reflect.Value) {
|
||||||
|
s := strconv.FormatInt(in.Int(), 10)
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) uintv(tag string, in reflect.Value) {
|
||||||
|
s := strconv.FormatUint(in.Uint(), 10)
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) timev(tag string, in reflect.Value) {
|
||||||
|
t := in.Interface().(time.Time)
|
||||||
|
s := t.Format(time.RFC3339Nano)
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) floatv(tag string, in reflect.Value) {
|
||||||
|
// Issue #352: When formatting, use the precision of the underlying value
|
||||||
|
precision := 64
|
||||||
|
if in.Kind() == reflect.Float32 {
|
||||||
|
precision = 32
|
||||||
|
}
|
||||||
|
|
||||||
|
s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
|
||||||
|
switch s {
|
||||||
|
case "+Inf":
|
||||||
|
s = ".inf"
|
||||||
|
case "-Inf":
|
||||||
|
s = "-.inf"
|
||||||
|
case "NaN":
|
||||||
|
s = ".nan"
|
||||||
|
}
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) nilv() {
|
||||||
|
e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) {
|
||||||
|
// TODO Kill this function. Replace all initialize calls by their underlining Go literals.
|
||||||
|
implicit := tag == ""
|
||||||
|
if !implicit {
|
||||||
|
tag = longTag(tag)
|
||||||
|
}
|
||||||
|
e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
|
||||||
|
e.event.head_comment = head
|
||||||
|
e.event.line_comment = line
|
||||||
|
e.event.foot_comment = foot
|
||||||
|
e.event.tail_comment = tail
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) nodev(in reflect.Value) {
|
||||||
|
e.node(in.Interface().(*Node), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) node(node *Node, tail string) {
|
||||||
|
// Zero nodes behave as nil.
|
||||||
|
if node.Kind == 0 && node.IsZero() {
|
||||||
|
e.nilv()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the tag was not explicitly requested, and dropping it won't change the
|
||||||
|
// implicit tag of the value, don't include it in the presentation.
|
||||||
|
var tag = node.Tag
|
||||||
|
var stag = shortTag(tag)
|
||||||
|
var forceQuoting bool
|
||||||
|
if tag != "" && node.Style&TaggedStyle == 0 {
|
||||||
|
if node.Kind == ScalarNode {
|
||||||
|
if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 {
|
||||||
|
tag = ""
|
||||||
|
} else {
|
||||||
|
rtag, _ := resolve("", node.Value)
|
||||||
|
if rtag == stag {
|
||||||
|
tag = ""
|
||||||
|
} else if stag == strTag {
|
||||||
|
tag = ""
|
||||||
|
forceQuoting = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var rtag string
|
||||||
|
switch node.Kind {
|
||||||
|
case MappingNode:
|
||||||
|
rtag = mapTag
|
||||||
|
case SequenceNode:
|
||||||
|
rtag = seqTag
|
||||||
|
}
|
||||||
|
if rtag == stag {
|
||||||
|
tag = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch node.Kind {
|
||||||
|
case DocumentNode:
|
||||||
|
yaml_document_start_event_initialize(&e.event, nil, nil, true)
|
||||||
|
e.event.head_comment = []byte(node.HeadComment)
|
||||||
|
e.emit()
|
||||||
|
for _, node := range node.Content {
|
||||||
|
e.node(node, "")
|
||||||
|
}
|
||||||
|
yaml_document_end_event_initialize(&e.event, true)
|
||||||
|
e.event.foot_comment = []byte(node.FootComment)
|
||||||
|
e.emit()
|
||||||
|
|
||||||
|
case SequenceNode:
|
||||||
|
style := yaml_BLOCK_SEQUENCE_STYLE
|
||||||
|
if node.Style&FlowStyle != 0 {
|
||||||
|
style = yaml_FLOW_SEQUENCE_STYLE
|
||||||
|
}
|
||||||
|
e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style))
|
||||||
|
e.event.head_comment = []byte(node.HeadComment)
|
||||||
|
e.emit()
|
||||||
|
for _, node := range node.Content {
|
||||||
|
e.node(node, "")
|
||||||
|
}
|
||||||
|
e.must(yaml_sequence_end_event_initialize(&e.event))
|
||||||
|
e.event.line_comment = []byte(node.LineComment)
|
||||||
|
e.event.foot_comment = []byte(node.FootComment)
|
||||||
|
e.emit()
|
||||||
|
|
||||||
|
case MappingNode:
|
||||||
|
style := yaml_BLOCK_MAPPING_STYLE
|
||||||
|
if node.Style&FlowStyle != 0 {
|
||||||
|
style = yaml_FLOW_MAPPING_STYLE
|
||||||
|
}
|
||||||
|
yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)
|
||||||
|
e.event.tail_comment = []byte(tail)
|
||||||
|
e.event.head_comment = []byte(node.HeadComment)
|
||||||
|
e.emit()
|
||||||
|
|
||||||
|
// The tail logic below moves the foot comment of prior keys to the following key,
|
||||||
|
// since the value for each key may be a nested structure and the foot needs to be
|
||||||
|
// processed only the entirety of the value is streamed. The last tail is processed
|
||||||
|
// with the mapping end event.
|
||||||
|
var tail string
|
||||||
|
for i := 0; i+1 < len(node.Content); i += 2 {
|
||||||
|
k := node.Content[i]
|
||||||
|
foot := k.FootComment
|
||||||
|
if foot != "" {
|
||||||
|
kopy := *k
|
||||||
|
kopy.FootComment = ""
|
||||||
|
k = &kopy
|
||||||
|
}
|
||||||
|
e.node(k, tail)
|
||||||
|
tail = foot
|
||||||
|
|
||||||
|
v := node.Content[i+1]
|
||||||
|
e.node(v, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
yaml_mapping_end_event_initialize(&e.event)
|
||||||
|
e.event.tail_comment = []byte(tail)
|
||||||
|
e.event.line_comment = []byte(node.LineComment)
|
||||||
|
e.event.foot_comment = []byte(node.FootComment)
|
||||||
|
e.emit()
|
||||||
|
|
||||||
|
case AliasNode:
|
||||||
|
yaml_alias_event_initialize(&e.event, []byte(node.Value))
|
||||||
|
e.event.head_comment = []byte(node.HeadComment)
|
||||||
|
e.event.line_comment = []byte(node.LineComment)
|
||||||
|
e.event.foot_comment = []byte(node.FootComment)
|
||||||
|
e.emit()
|
||||||
|
|
||||||
|
case ScalarNode:
|
||||||
|
value := node.Value
|
||||||
|
if !utf8.ValidString(value) {
|
||||||
|
if stag == binaryTag {
|
||||||
|
failf("explicitly tagged !!binary data must be base64-encoded")
|
||||||
|
}
|
||||||
|
if stag != "" {
|
||||||
|
failf("cannot marshal invalid UTF-8 data as %s", stag)
|
||||||
|
}
|
||||||
|
// It can't be encoded directly as YAML so use a binary tag
|
||||||
|
// and encode it as base64.
|
||||||
|
tag = binaryTag
|
||||||
|
value = encodeBase64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
style := yaml_PLAIN_SCALAR_STYLE
|
||||||
|
switch {
|
||||||
|
case node.Style&DoubleQuotedStyle != 0:
|
||||||
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
||||||
|
case node.Style&SingleQuotedStyle != 0:
|
||||||
|
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
|
||||||
|
case node.Style&LiteralStyle != 0:
|
||||||
|
style = yaml_LITERAL_SCALAR_STYLE
|
||||||
|
case node.Style&FoldedStyle != 0:
|
||||||
|
style = yaml_FOLDED_SCALAR_STYLE
|
||||||
|
case strings.Contains(value, "\n"):
|
||||||
|
style = yaml_LITERAL_SCALAR_STYLE
|
||||||
|
case forceQuoting:
|
||||||
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
||||||
|
}
|
||||||
|
|
||||||
|
e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail))
|
||||||
|
default:
|
||||||
|
failf("cannot encode node with unknown kind %d", node.Kind)
|
||||||
|
}
|
||||||
|
}
|
1249
vendor/gopkg.in/yaml.v3/parserc.go
generated
vendored
Normal file
1249
vendor/gopkg.in/yaml.v3/parserc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
434
vendor/gopkg.in/yaml.v3/readerc.go
generated
vendored
Normal file
434
vendor/gopkg.in/yaml.v3/readerc.go
generated
vendored
Normal file
|
@ -0,0 +1,434 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
// Copyright (c) 2006-2010 Kirill Simonov
|
||||||
|
//
|
||||||
|
// 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 yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set the reader error and return 0.
|
||||||
|
func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
|
||||||
|
parser.error = yaml_READER_ERROR
|
||||||
|
parser.problem = problem
|
||||||
|
parser.problem_offset = offset
|
||||||
|
parser.problem_value = value
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte order marks.
|
||||||
|
const (
|
||||||
|
bom_UTF8 = "\xef\xbb\xbf"
|
||||||
|
bom_UTF16LE = "\xff\xfe"
|
||||||
|
bom_UTF16BE = "\xfe\xff"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Determine the input stream encoding by checking the BOM symbol. If no BOM is
|
||||||
|
// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
|
||||||
|
func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
|
||||||
|
// Ensure that we had enough bytes in the raw buffer.
|
||||||
|
for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
|
||||||
|
if !yaml_parser_update_raw_buffer(parser) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the encoding.
|
||||||
|
buf := parser.raw_buffer
|
||||||
|
pos := parser.raw_buffer_pos
|
||||||
|
avail := len(buf) - pos
|
||||||
|
if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
|
||||||
|
parser.encoding = yaml_UTF16LE_ENCODING
|
||||||
|
parser.raw_buffer_pos += 2
|
||||||
|
parser.offset += 2
|
||||||
|
} else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
|
||||||
|
parser.encoding = yaml_UTF16BE_ENCODING
|
||||||
|
parser.raw_buffer_pos += 2
|
||||||
|
parser.offset += 2
|
||||||
|
} else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
|
||||||
|
parser.encoding = yaml_UTF8_ENCODING
|
||||||
|
parser.raw_buffer_pos += 3
|
||||||
|
parser.offset += 3
|
||||||
|
} else {
|
||||||
|
parser.encoding = yaml_UTF8_ENCODING
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the raw buffer.
|
||||||
|
func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
|
||||||
|
size_read := 0
|
||||||
|
|
||||||
|
// Return if the raw buffer is full.
|
||||||
|
if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return on EOF.
|
||||||
|
if parser.eof {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the remaining bytes in the raw buffer to the beginning.
|
||||||
|
if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
|
||||||
|
copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
|
||||||
|
}
|
||||||
|
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
|
||||||
|
parser.raw_buffer_pos = 0
|
||||||
|
|
||||||
|
// Call the read handler to fill the buffer.
|
||||||
|
size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
|
||||||
|
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
|
||||||
|
if err == io.EOF {
|
||||||
|
parser.eof = true
|
||||||
|
} else if err != nil {
|
||||||
|
return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the buffer contains at least `length` characters.
|
||||||
|
// Return true on success, false on failure.
|
||||||
|
//
|
||||||
|
// The length is supposed to be significantly less that the buffer size.
|
||||||
|
func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
|
||||||
|
if parser.read_handler == nil {
|
||||||
|
panic("read handler must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// [Go] This function was changed to guarantee the requested length size at EOF.
|
||||||
|
// The fact we need to do this is pretty awful, but the description above implies
|
||||||
|
// for that to be the case, and there are tests
|
||||||
|
|
||||||
|
// If the EOF flag is set and the raw buffer is empty, do nothing.
|
||||||
|
if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
|
||||||
|
// [Go] ACTUALLY! Read the documentation of this function above.
|
||||||
|
// This is just broken. To return true, we need to have the
|
||||||
|
// given length in the buffer. Not doing that means every single
|
||||||
|
// check that calls this function to make sure the buffer has a
|
||||||
|
// given length is Go) panicking; or C) accessing invalid memory.
|
||||||
|
//return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if the buffer contains enough characters.
|
||||||
|
if parser.unread >= length {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the input encoding if it is not known yet.
|
||||||
|
if parser.encoding == yaml_ANY_ENCODING {
|
||||||
|
if !yaml_parser_determine_encoding(parser) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the unread characters to the beginning of the buffer.
|
||||||
|
buffer_len := len(parser.buffer)
|
||||||
|
if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
|
||||||
|
copy(parser.buffer, parser.buffer[parser.buffer_pos:])
|
||||||
|
buffer_len -= parser.buffer_pos
|
||||||
|
parser.buffer_pos = 0
|
||||||
|
} else if parser.buffer_pos == buffer_len {
|
||||||
|
buffer_len = 0
|
||||||
|
parser.buffer_pos = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the whole buffer for writing, and cut it before returning.
|
||||||
|
parser.buffer = parser.buffer[:cap(parser.buffer)]
|
||||||
|
|
||||||
|
// Fill the buffer until it has enough characters.
|
||||||
|
first := true
|
||||||
|
for parser.unread < length {
|
||||||
|
|
||||||
|
// Fill the raw buffer if necessary.
|
||||||
|
if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
|
||||||
|
if !yaml_parser_update_raw_buffer(parser) {
|
||||||
|
parser.buffer = parser.buffer[:buffer_len]
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first = false
|
||||||
|
|
||||||
|
// Decode the raw buffer.
|
||||||
|
inner:
|
||||||
|
for parser.raw_buffer_pos != len(parser.raw_buffer) {
|
||||||
|
var value rune
|
||||||
|
var width int
|
||||||
|
|
||||||
|
raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
|
||||||
|
|
||||||
|
// Decode the next character.
|
||||||
|
switch parser.encoding {
|
||||||
|
case yaml_UTF8_ENCODING:
|
||||||
|
// Decode a UTF-8 character. Check RFC 3629
|
||||||
|
// (http://www.ietf.org/rfc/rfc3629.txt) for more details.
|
||||||
|
//
|
||||||
|
// The following table (taken from the RFC) is used for
|
||||||
|
// decoding.
|
||||||
|
//
|
||||||
|
// Char. number range | UTF-8 octet sequence
|
||||||
|
// (hexadecimal) | (binary)
|
||||||
|
// --------------------+------------------------------------
|
||||||
|
// 0000 0000-0000 007F | 0xxxxxxx
|
||||||
|
// 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
|
||||||
|
// 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
// 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
//
|
||||||
|
// Additionally, the characters in the range 0xD800-0xDFFF
|
||||||
|
// are prohibited as they are reserved for use with UTF-16
|
||||||
|
// surrogate pairs.
|
||||||
|
|
||||||
|
// Determine the length of the UTF-8 sequence.
|
||||||
|
octet := parser.raw_buffer[parser.raw_buffer_pos]
|
||||||
|
switch {
|
||||||
|
case octet&0x80 == 0x00:
|
||||||
|
width = 1
|
||||||
|
case octet&0xE0 == 0xC0:
|
||||||
|
width = 2
|
||||||
|
case octet&0xF0 == 0xE0:
|
||||||
|
width = 3
|
||||||
|
case octet&0xF8 == 0xF0:
|
||||||
|
width = 4
|
||||||
|
default:
|
||||||
|
// The leading octet is invalid.
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid leading UTF-8 octet",
|
||||||
|
parser.offset, int(octet))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the raw buffer contains an incomplete character.
|
||||||
|
if width > raw_unread {
|
||||||
|
if parser.eof {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"incomplete UTF-8 octet sequence",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
break inner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the leading octet.
|
||||||
|
switch {
|
||||||
|
case octet&0x80 == 0x00:
|
||||||
|
value = rune(octet & 0x7F)
|
||||||
|
case octet&0xE0 == 0xC0:
|
||||||
|
value = rune(octet & 0x1F)
|
||||||
|
case octet&0xF0 == 0xE0:
|
||||||
|
value = rune(octet & 0x0F)
|
||||||
|
case octet&0xF8 == 0xF0:
|
||||||
|
value = rune(octet & 0x07)
|
||||||
|
default:
|
||||||
|
value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and decode the trailing octets.
|
||||||
|
for k := 1; k < width; k++ {
|
||||||
|
octet = parser.raw_buffer[parser.raw_buffer_pos+k]
|
||||||
|
|
||||||
|
// Check if the octet is valid.
|
||||||
|
if (octet & 0xC0) != 0x80 {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid trailing UTF-8 octet",
|
||||||
|
parser.offset+k, int(octet))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the octet.
|
||||||
|
value = (value << 6) + rune(octet&0x3F)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the length of the sequence against the value.
|
||||||
|
switch {
|
||||||
|
case width == 1:
|
||||||
|
case width == 2 && value >= 0x80:
|
||||||
|
case width == 3 && value >= 0x800:
|
||||||
|
case width == 4 && value >= 0x10000:
|
||||||
|
default:
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid length of a UTF-8 sequence",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the range of the value.
|
||||||
|
if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid Unicode character",
|
||||||
|
parser.offset, int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
|
||||||
|
var low, high int
|
||||||
|
if parser.encoding == yaml_UTF16LE_ENCODING {
|
||||||
|
low, high = 0, 1
|
||||||
|
} else {
|
||||||
|
low, high = 1, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// The UTF-16 encoding is not as simple as one might
|
||||||
|
// naively think. Check RFC 2781
|
||||||
|
// (http://www.ietf.org/rfc/rfc2781.txt).
|
||||||
|
//
|
||||||
|
// Normally, two subsequent bytes describe a Unicode
|
||||||
|
// character. However a special technique (called a
|
||||||
|
// surrogate pair) is used for specifying character
|
||||||
|
// values larger than 0xFFFF.
|
||||||
|
//
|
||||||
|
// A surrogate pair consists of two pseudo-characters:
|
||||||
|
// high surrogate area (0xD800-0xDBFF)
|
||||||
|
// low surrogate area (0xDC00-0xDFFF)
|
||||||
|
//
|
||||||
|
// The following formulas are used for decoding
|
||||||
|
// and encoding characters using surrogate pairs:
|
||||||
|
//
|
||||||
|
// U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
|
||||||
|
// U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
|
||||||
|
// W1 = 110110yyyyyyyyyy
|
||||||
|
// W2 = 110111xxxxxxxxxx
|
||||||
|
//
|
||||||
|
// where U is the character value, W1 is the high surrogate
|
||||||
|
// area, W2 is the low surrogate area.
|
||||||
|
|
||||||
|
// Check for incomplete UTF-16 character.
|
||||||
|
if raw_unread < 2 {
|
||||||
|
if parser.eof {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"incomplete UTF-16 character",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
break inner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the character.
|
||||||
|
value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
|
||||||
|
(rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
|
||||||
|
|
||||||
|
// Check for unexpected low surrogate area.
|
||||||
|
if value&0xFC00 == 0xDC00 {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"unexpected low surrogate area",
|
||||||
|
parser.offset, int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a high surrogate area.
|
||||||
|
if value&0xFC00 == 0xD800 {
|
||||||
|
width = 4
|
||||||
|
|
||||||
|
// Check for incomplete surrogate pair.
|
||||||
|
if raw_unread < 4 {
|
||||||
|
if parser.eof {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"incomplete UTF-16 surrogate pair",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
break inner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next character.
|
||||||
|
value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
|
||||||
|
(rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
|
||||||
|
|
||||||
|
// Check for a low surrogate area.
|
||||||
|
if value2&0xFC00 != 0xDC00 {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"expected low surrogate area",
|
||||||
|
parser.offset+2, int(value2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the value of the surrogate pair.
|
||||||
|
value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
|
||||||
|
} else {
|
||||||
|
width = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("impossible")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character is in the allowed range:
|
||||||
|
// #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
|
||||||
|
// | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
|
||||||
|
// | [#x10000-#x10FFFF] (32 bit)
|
||||||
|
switch {
|
||||||
|
case value == 0x09:
|
||||||
|
case value == 0x0A:
|
||||||
|
case value == 0x0D:
|
||||||
|
case value >= 0x20 && value <= 0x7E:
|
||||||
|
case value == 0x85:
|
||||||
|
case value >= 0xA0 && value <= 0xD7FF:
|
||||||
|
case value >= 0xE000 && value <= 0xFFFD:
|
||||||
|
case value >= 0x10000 && value <= 0x10FFFF:
|
||||||
|
default:
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"control characters are not allowed",
|
||||||
|
parser.offset, int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the raw pointers.
|
||||||
|
parser.raw_buffer_pos += width
|
||||||
|
parser.offset += width
|
||||||
|
|
||||||
|
// Finally put the character into the buffer.
|
||||||
|
if value <= 0x7F {
|
||||||
|
// 0000 0000-0000 007F . 0xxxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(value)
|
||||||
|
buffer_len += 1
|
||||||
|
} else if value <= 0x7FF {
|
||||||
|
// 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
|
||||||
|
parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
|
||||||
|
buffer_len += 2
|
||||||
|
} else if value <= 0xFFFF {
|
||||||
|
// 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
|
||||||
|
parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
|
||||||
|
parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
|
||||||
|
buffer_len += 3
|
||||||
|
} else {
|
||||||
|
// 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
|
||||||
|
parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
|
||||||
|
parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
|
||||||
|
parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
|
||||||
|
buffer_len += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.unread++
|
||||||
|
}
|
||||||
|
|
||||||
|
// On EOF, put NUL into the buffer and return.
|
||||||
|
if parser.eof {
|
||||||
|
parser.buffer[buffer_len] = 0
|
||||||
|
buffer_len++
|
||||||
|
parser.unread++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// [Go] Read the documentation of this function above. To return true,
|
||||||
|
// we need to have the given length in the buffer. Not doing that means
|
||||||
|
// every single check that calls this function to make sure the buffer
|
||||||
|
// has a given length is Go) panicking; or C) accessing invalid memory.
|
||||||
|
// This happens here due to the EOF above breaking early.
|
||||||
|
for buffer_len < length {
|
||||||
|
parser.buffer[buffer_len] = 0
|
||||||
|
buffer_len++
|
||||||
|
}
|
||||||
|
parser.buffer = parser.buffer[:buffer_len]
|
||||||
|
return true
|
||||||
|
}
|
326
vendor/gopkg.in/yaml.v3/resolve.go
generated
vendored
Normal file
326
vendor/gopkg.in/yaml.v3/resolve.go
generated
vendored
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type resolveMapItem struct {
|
||||||
|
value interface{}
|
||||||
|
tag string
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolveTable = make([]byte, 256)
|
||||||
|
var resolveMap = make(map[string]resolveMapItem)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
t := resolveTable
|
||||||
|
t[int('+')] = 'S' // Sign
|
||||||
|
t[int('-')] = 'S'
|
||||||
|
for _, c := range "0123456789" {
|
||||||
|
t[int(c)] = 'D' // Digit
|
||||||
|
}
|
||||||
|
for _, c := range "yYnNtTfFoO~" {
|
||||||
|
t[int(c)] = 'M' // In map
|
||||||
|
}
|
||||||
|
t[int('.')] = '.' // Float (potentially in map)
|
||||||
|
|
||||||
|
var resolveMapList = []struct {
|
||||||
|
v interface{}
|
||||||
|
tag string
|
||||||
|
l []string
|
||||||
|
}{
|
||||||
|
{true, boolTag, []string{"true", "True", "TRUE"}},
|
||||||
|
{false, boolTag, []string{"false", "False", "FALSE"}},
|
||||||
|
{nil, nullTag, []string{"", "~", "null", "Null", "NULL"}},
|
||||||
|
{math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}},
|
||||||
|
{math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}},
|
||||||
|
{math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}},
|
||||||
|
{math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}},
|
||||||
|
{"<<", mergeTag, []string{"<<"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
m := resolveMap
|
||||||
|
for _, item := range resolveMapList {
|
||||||
|
for _, s := range item.l {
|
||||||
|
m[s] = resolveMapItem{item.v, item.tag}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
nullTag = "!!null"
|
||||||
|
boolTag = "!!bool"
|
||||||
|
strTag = "!!str"
|
||||||
|
intTag = "!!int"
|
||||||
|
floatTag = "!!float"
|
||||||
|
timestampTag = "!!timestamp"
|
||||||
|
seqTag = "!!seq"
|
||||||
|
mapTag = "!!map"
|
||||||
|
binaryTag = "!!binary"
|
||||||
|
mergeTag = "!!merge"
|
||||||
|
)
|
||||||
|
|
||||||
|
var longTags = make(map[string]string)
|
||||||
|
var shortTags = make(map[string]string)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} {
|
||||||
|
ltag := longTag(stag)
|
||||||
|
longTags[stag] = ltag
|
||||||
|
shortTags[ltag] = stag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const longTagPrefix = "tag:yaml.org,2002:"
|
||||||
|
|
||||||
|
func shortTag(tag string) string {
|
||||||
|
if strings.HasPrefix(tag, longTagPrefix) {
|
||||||
|
if stag, ok := shortTags[tag]; ok {
|
||||||
|
return stag
|
||||||
|
}
|
||||||
|
return "!!" + tag[len(longTagPrefix):]
|
||||||
|
}
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func longTag(tag string) string {
|
||||||
|
if strings.HasPrefix(tag, "!!") {
|
||||||
|
if ltag, ok := longTags[tag]; ok {
|
||||||
|
return ltag
|
||||||
|
}
|
||||||
|
return longTagPrefix + tag[2:]
|
||||||
|
}
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolvableTag(tag string) bool {
|
||||||
|
switch tag {
|
||||||
|
case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
|
||||||
|
|
||||||
|
func resolve(tag string, in string) (rtag string, out interface{}) {
|
||||||
|
tag = shortTag(tag)
|
||||||
|
if !resolvableTag(tag) {
|
||||||
|
return tag, in
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
switch tag {
|
||||||
|
case "", rtag, strTag, binaryTag:
|
||||||
|
return
|
||||||
|
case floatTag:
|
||||||
|
if rtag == intTag {
|
||||||
|
switch v := out.(type) {
|
||||||
|
case int64:
|
||||||
|
rtag = floatTag
|
||||||
|
out = float64(v)
|
||||||
|
return
|
||||||
|
case int:
|
||||||
|
rtag = floatTag
|
||||||
|
out = float64(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Any data is accepted as a !!str or !!binary.
|
||||||
|
// Otherwise, the prefix is enough of a hint about what it might be.
|
||||||
|
hint := byte('N')
|
||||||
|
if in != "" {
|
||||||
|
hint = resolveTable[in[0]]
|
||||||
|
}
|
||||||
|
if hint != 0 && tag != strTag && tag != binaryTag {
|
||||||
|
// Handle things we can lookup in a map.
|
||||||
|
if item, ok := resolveMap[in]; ok {
|
||||||
|
return item.tag, item.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base 60 floats are a bad idea, were dropped in YAML 1.2, and
|
||||||
|
// are purposefully unsupported here. They're still quoted on
|
||||||
|
// the way out for compatibility with other parser, though.
|
||||||
|
|
||||||
|
switch hint {
|
||||||
|
case 'M':
|
||||||
|
// We've already checked the map above.
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
// Not in the map, so maybe a normal float.
|
||||||
|
floatv, err := strconv.ParseFloat(in, 64)
|
||||||
|
if err == nil {
|
||||||
|
return floatTag, floatv
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'D', 'S':
|
||||||
|
// Int, float, or timestamp.
|
||||||
|
// Only try values as a timestamp if the value is unquoted or there's an explicit
|
||||||
|
// !!timestamp tag.
|
||||||
|
if tag == "" || tag == timestampTag {
|
||||||
|
t, ok := parseTimestamp(in)
|
||||||
|
if ok {
|
||||||
|
return timestampTag, t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plain := strings.Replace(in, "_", "", -1)
|
||||||
|
intv, err := strconv.ParseInt(plain, 0, 64)
|
||||||
|
if err == nil {
|
||||||
|
if intv == int64(int(intv)) {
|
||||||
|
return intTag, int(intv)
|
||||||
|
} else {
|
||||||
|
return intTag, intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uintv, err := strconv.ParseUint(plain, 0, 64)
|
||||||
|
if err == nil {
|
||||||
|
return intTag, uintv
|
||||||
|
}
|
||||||
|
if yamlStyleFloat.MatchString(plain) {
|
||||||
|
floatv, err := strconv.ParseFloat(plain, 64)
|
||||||
|
if err == nil {
|
||||||
|
return floatTag, floatv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(plain, "0b") {
|
||||||
|
intv, err := strconv.ParseInt(plain[2:], 2, 64)
|
||||||
|
if err == nil {
|
||||||
|
if intv == int64(int(intv)) {
|
||||||
|
return intTag, int(intv)
|
||||||
|
} else {
|
||||||
|
return intTag, intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uintv, err := strconv.ParseUint(plain[2:], 2, 64)
|
||||||
|
if err == nil {
|
||||||
|
return intTag, uintv
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(plain, "-0b") {
|
||||||
|
intv, err := strconv.ParseInt("-"+plain[3:], 2, 64)
|
||||||
|
if err == nil {
|
||||||
|
if true || intv == int64(int(intv)) {
|
||||||
|
return intTag, int(intv)
|
||||||
|
} else {
|
||||||
|
return intTag, intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Octals as introduced in version 1.2 of the spec.
|
||||||
|
// Octals from the 1.1 spec, spelled as 0777, are still
|
||||||
|
// decoded by default in v3 as well for compatibility.
|
||||||
|
// May be dropped in v4 depending on how usage evolves.
|
||||||
|
if strings.HasPrefix(plain, "0o") {
|
||||||
|
intv, err := strconv.ParseInt(plain[2:], 8, 64)
|
||||||
|
if err == nil {
|
||||||
|
if intv == int64(int(intv)) {
|
||||||
|
return intTag, int(intv)
|
||||||
|
} else {
|
||||||
|
return intTag, intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uintv, err := strconv.ParseUint(plain[2:], 8, 64)
|
||||||
|
if err == nil {
|
||||||
|
return intTag, uintv
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(plain, "-0o") {
|
||||||
|
intv, err := strconv.ParseInt("-"+plain[3:], 8, 64)
|
||||||
|
if err == nil {
|
||||||
|
if true || intv == int64(int(intv)) {
|
||||||
|
return intTag, int(intv)
|
||||||
|
} else {
|
||||||
|
return intTag, intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strTag, in
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeBase64 encodes s as base64 that is broken up into multiple lines
|
||||||
|
// as appropriate for the resulting length.
|
||||||
|
func encodeBase64(s string) string {
|
||||||
|
const lineLen = 70
|
||||||
|
encLen := base64.StdEncoding.EncodedLen(len(s))
|
||||||
|
lines := encLen/lineLen + 1
|
||||||
|
buf := make([]byte, encLen*2+lines)
|
||||||
|
in := buf[0:encLen]
|
||||||
|
out := buf[encLen:]
|
||||||
|
base64.StdEncoding.Encode(in, []byte(s))
|
||||||
|
k := 0
|
||||||
|
for i := 0; i < len(in); i += lineLen {
|
||||||
|
j := i + lineLen
|
||||||
|
if j > len(in) {
|
||||||
|
j = len(in)
|
||||||
|
}
|
||||||
|
k += copy(out[k:], in[i:j])
|
||||||
|
if lines > 1 {
|
||||||
|
out[k] = '\n'
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(out[:k])
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a subset of the formats allowed by the regular expression
|
||||||
|
// defined at http://yaml.org/type/timestamp.html.
|
||||||
|
var allowedTimestampFormats = []string{
|
||||||
|
"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
|
||||||
|
"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
|
||||||
|
"2006-1-2 15:4:5.999999999", // space separated with no time zone
|
||||||
|
"2006-1-2", // date only
|
||||||
|
// Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
|
||||||
|
// from the set of examples.
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseTimestamp parses s as a timestamp string and
|
||||||
|
// returns the timestamp and reports whether it succeeded.
|
||||||
|
// Timestamp formats are defined at http://yaml.org/type/timestamp.html
|
||||||
|
func parseTimestamp(s string) (time.Time, bool) {
|
||||||
|
// TODO write code to check all the formats supported by
|
||||||
|
// http://yaml.org/type/timestamp.html instead of using time.Parse.
|
||||||
|
|
||||||
|
// Quick check: all date formats start with YYYY-.
|
||||||
|
i := 0
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
if c := s[i]; c < '0' || c > '9' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i != 4 || i == len(s) || s[i] != '-' {
|
||||||
|
return time.Time{}, false
|
||||||
|
}
|
||||||
|
for _, format := range allowedTimestampFormats {
|
||||||
|
if t, err := time.Parse(format, s); err == nil {
|
||||||
|
return t, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return time.Time{}, false
|
||||||
|
}
|
3038
vendor/gopkg.in/yaml.v3/scannerc.go
generated
vendored
Normal file
3038
vendor/gopkg.in/yaml.v3/scannerc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
134
vendor/gopkg.in/yaml.v3/sorter.go
generated
vendored
Normal file
134
vendor/gopkg.in/yaml.v3/sorter.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type keyList []reflect.Value
|
||||||
|
|
||||||
|
func (l keyList) Len() int { return len(l) }
|
||||||
|
func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
||||||
|
func (l keyList) Less(i, j int) bool {
|
||||||
|
a := l[i]
|
||||||
|
b := l[j]
|
||||||
|
ak := a.Kind()
|
||||||
|
bk := b.Kind()
|
||||||
|
for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
|
||||||
|
a = a.Elem()
|
||||||
|
ak = a.Kind()
|
||||||
|
}
|
||||||
|
for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
|
||||||
|
b = b.Elem()
|
||||||
|
bk = b.Kind()
|
||||||
|
}
|
||||||
|
af, aok := keyFloat(a)
|
||||||
|
bf, bok := keyFloat(b)
|
||||||
|
if aok && bok {
|
||||||
|
if af != bf {
|
||||||
|
return af < bf
|
||||||
|
}
|
||||||
|
if ak != bk {
|
||||||
|
return ak < bk
|
||||||
|
}
|
||||||
|
return numLess(a, b)
|
||||||
|
}
|
||||||
|
if ak != reflect.String || bk != reflect.String {
|
||||||
|
return ak < bk
|
||||||
|
}
|
||||||
|
ar, br := []rune(a.String()), []rune(b.String())
|
||||||
|
digits := false
|
||||||
|
for i := 0; i < len(ar) && i < len(br); i++ {
|
||||||
|
if ar[i] == br[i] {
|
||||||
|
digits = unicode.IsDigit(ar[i])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
al := unicode.IsLetter(ar[i])
|
||||||
|
bl := unicode.IsLetter(br[i])
|
||||||
|
if al && bl {
|
||||||
|
return ar[i] < br[i]
|
||||||
|
}
|
||||||
|
if al || bl {
|
||||||
|
if digits {
|
||||||
|
return al
|
||||||
|
} else {
|
||||||
|
return bl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ai, bi int
|
||||||
|
var an, bn int64
|
||||||
|
if ar[i] == '0' || br[i] == '0' {
|
||||||
|
for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
|
||||||
|
if ar[j] != '0' {
|
||||||
|
an = 1
|
||||||
|
bn = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
|
||||||
|
an = an*10 + int64(ar[ai]-'0')
|
||||||
|
}
|
||||||
|
for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
|
||||||
|
bn = bn*10 + int64(br[bi]-'0')
|
||||||
|
}
|
||||||
|
if an != bn {
|
||||||
|
return an < bn
|
||||||
|
}
|
||||||
|
if ai != bi {
|
||||||
|
return ai < bi
|
||||||
|
}
|
||||||
|
return ar[i] < br[i]
|
||||||
|
}
|
||||||
|
return len(ar) < len(br)
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyFloat returns a float value for v if it is a number/bool
|
||||||
|
// and whether it is a number/bool or not.
|
||||||
|
func keyFloat(v reflect.Value) (f float64, ok bool) {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return float64(v.Int()), true
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float(), true
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return float64(v.Uint()), true
|
||||||
|
case reflect.Bool:
|
||||||
|
if v.Bool() {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// numLess returns whether a < b.
|
||||||
|
// a and b must necessarily have the same kind.
|
||||||
|
func numLess(a, b reflect.Value) bool {
|
||||||
|
switch a.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return a.Int() < b.Int()
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return a.Float() < b.Float()
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Bool:
|
||||||
|
return !a.Bool() && b.Bool()
|
||||||
|
}
|
||||||
|
panic("not a number")
|
||||||
|
}
|
48
vendor/gopkg.in/yaml.v3/writerc.go
generated
vendored
Normal file
48
vendor/gopkg.in/yaml.v3/writerc.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
// Copyright (c) 2006-2010 Kirill Simonov
|
||||||
|
//
|
||||||
|
// 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 yaml
|
||||||
|
|
||||||
|
// Set the writer error and return false.
|
||||||
|
func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
|
||||||
|
emitter.error = yaml_WRITER_ERROR
|
||||||
|
emitter.problem = problem
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the output buffer.
|
||||||
|
func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
|
||||||
|
if emitter.write_handler == nil {
|
||||||
|
panic("write handler not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the buffer is empty.
|
||||||
|
if emitter.buffer_pos == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
|
||||||
|
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
|
||||||
|
}
|
||||||
|
emitter.buffer_pos = 0
|
||||||
|
return true
|
||||||
|
}
|
698
vendor/gopkg.in/yaml.v3/yaml.go
generated
vendored
Normal file
698
vendor/gopkg.in/yaml.v3/yaml.go
generated
vendored
Normal file
|
@ -0,0 +1,698 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package yaml implements YAML support for the Go language.
|
||||||
|
//
|
||||||
|
// Source code and other details for the project are available at GitHub:
|
||||||
|
//
|
||||||
|
// https://github.com/go-yaml/yaml
|
||||||
|
//
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The Unmarshaler interface may be implemented by types to customize their
|
||||||
|
// behavior when being unmarshaled from a YAML document.
|
||||||
|
type Unmarshaler interface {
|
||||||
|
UnmarshalYAML(value *Node) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type obsoleteUnmarshaler interface {
|
||||||
|
UnmarshalYAML(unmarshal func(interface{}) error) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Marshaler interface may be implemented by types to customize their
|
||||||
|
// behavior when being marshaled into a YAML document. The returned value
|
||||||
|
// is marshaled in place of the original value implementing Marshaler.
|
||||||
|
//
|
||||||
|
// If an error is returned by MarshalYAML, the marshaling procedure stops
|
||||||
|
// and returns with the provided error.
|
||||||
|
type Marshaler interface {
|
||||||
|
MarshalYAML() (interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal decodes the first document found within the in byte slice
|
||||||
|
// and assigns decoded values into the out value.
|
||||||
|
//
|
||||||
|
// Maps and pointers (to a struct, string, int, etc) are accepted as out
|
||||||
|
// values. If an internal pointer within a struct is not initialized,
|
||||||
|
// the yaml package will initialize it if necessary for unmarshalling
|
||||||
|
// the provided data. The out parameter must not be nil.
|
||||||
|
//
|
||||||
|
// The type of the decoded values should be compatible with the respective
|
||||||
|
// values in out. If one or more values cannot be decoded due to a type
|
||||||
|
// mismatches, decoding continues partially until the end of the YAML
|
||||||
|
// content, and a *yaml.TypeError is returned with details for all
|
||||||
|
// missed values.
|
||||||
|
//
|
||||||
|
// Struct fields are only unmarshalled if they are exported (have an
|
||||||
|
// upper case first letter), and are unmarshalled using the field name
|
||||||
|
// lowercased as the default key. Custom keys may be defined via the
|
||||||
|
// "yaml" name in the field tag: the content preceding the first comma
|
||||||
|
// is used as the key, and the following comma-separated options are
|
||||||
|
// used to tweak the marshalling process (see Marshal).
|
||||||
|
// Conflicting names result in a runtime error.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// type T struct {
|
||||||
|
// F int `yaml:"a,omitempty"`
|
||||||
|
// B int
|
||||||
|
// }
|
||||||
|
// var t T
|
||||||
|
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||||
|
//
|
||||||
|
// See the documentation of Marshal for the format of tags and a list of
|
||||||
|
// supported tag options.
|
||||||
|
//
|
||||||
|
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||||
|
return unmarshal(in, out, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Decoder reads and decodes YAML values from an input stream.
|
||||||
|
type Decoder struct {
|
||||||
|
parser *parser
|
||||||
|
knownFields bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a new decoder that reads from r.
|
||||||
|
//
|
||||||
|
// The decoder introduces its own buffering and may read
|
||||||
|
// data from r beyond the YAML values requested.
|
||||||
|
func NewDecoder(r io.Reader) *Decoder {
|
||||||
|
return &Decoder{
|
||||||
|
parser: newParserFromReader(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// KnownFields ensures that the keys in decoded mappings to
|
||||||
|
// exist as fields in the struct being decoded into.
|
||||||
|
func (dec *Decoder) KnownFields(enable bool) {
|
||||||
|
dec.knownFields = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode reads the next YAML-encoded value from its input
|
||||||
|
// and stores it in the value pointed to by v.
|
||||||
|
//
|
||||||
|
// See the documentation for Unmarshal for details about the
|
||||||
|
// conversion of YAML into a Go value.
|
||||||
|
func (dec *Decoder) Decode(v interface{}) (err error) {
|
||||||
|
d := newDecoder()
|
||||||
|
d.knownFields = dec.knownFields
|
||||||
|
defer handleErr(&err)
|
||||||
|
node := dec.parser.parse()
|
||||||
|
if node == nil {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
out := reflect.ValueOf(v)
|
||||||
|
if out.Kind() == reflect.Ptr && !out.IsNil() {
|
||||||
|
out = out.Elem()
|
||||||
|
}
|
||||||
|
d.unmarshal(node, out)
|
||||||
|
if len(d.terrors) > 0 {
|
||||||
|
return &TypeError{d.terrors}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode decodes the node and stores its data into the value pointed to by v.
|
||||||
|
//
|
||||||
|
// See the documentation for Unmarshal for details about the
|
||||||
|
// conversion of YAML into a Go value.
|
||||||
|
func (n *Node) Decode(v interface{}) (err error) {
|
||||||
|
d := newDecoder()
|
||||||
|
defer handleErr(&err)
|
||||||
|
out := reflect.ValueOf(v)
|
||||||
|
if out.Kind() == reflect.Ptr && !out.IsNil() {
|
||||||
|
out = out.Elem()
|
||||||
|
}
|
||||||
|
d.unmarshal(n, out)
|
||||||
|
if len(d.terrors) > 0 {
|
||||||
|
return &TypeError{d.terrors}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
d := newDecoder()
|
||||||
|
p := newParser(in)
|
||||||
|
defer p.destroy()
|
||||||
|
node := p.parse()
|
||||||
|
if node != nil {
|
||||||
|
v := reflect.ValueOf(out)
|
||||||
|
if v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
d.unmarshal(node, v)
|
||||||
|
}
|
||||||
|
if len(d.terrors) > 0 {
|
||||||
|
return &TypeError{d.terrors}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal serializes the value provided into a YAML document. The structure
|
||||||
|
// of the generated document will reflect the structure of the value itself.
|
||||||
|
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
|
||||||
|
//
|
||||||
|
// Struct fields are only marshalled if they are exported (have an upper case
|
||||||
|
// first letter), and are marshalled using the field name lowercased as the
|
||||||
|
// default key. Custom keys may be defined via the "yaml" name in the field
|
||||||
|
// tag: the content preceding the first comma is used as the key, and the
|
||||||
|
// following comma-separated options are used to tweak the marshalling process.
|
||||||
|
// Conflicting names result in a runtime error.
|
||||||
|
//
|
||||||
|
// The field tag format accepted is:
|
||||||
|
//
|
||||||
|
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||||
|
//
|
||||||
|
// The following flags are currently supported:
|
||||||
|
//
|
||||||
|
// omitempty Only include the field if it's not set to the zero
|
||||||
|
// value for the type or to empty slices or maps.
|
||||||
|
// Zero valued structs will be omitted if all their public
|
||||||
|
// fields are zero, unless they implement an IsZero
|
||||||
|
// method (see the IsZeroer interface type), in which
|
||||||
|
// case the field will be excluded if IsZero returns true.
|
||||||
|
//
|
||||||
|
// flow Marshal using a flow style (useful for structs,
|
||||||
|
// sequences and maps).
|
||||||
|
//
|
||||||
|
// inline Inline the field, which must be a struct or a map,
|
||||||
|
// causing all of its fields or keys to be processed as if
|
||||||
|
// they were part of the outer struct. For maps, keys must
|
||||||
|
// not conflict with the yaml keys of other struct fields.
|
||||||
|
//
|
||||||
|
// In addition, if the key is "-", the field is ignored.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// type T struct {
|
||||||
|
// F int `yaml:"a,omitempty"`
|
||||||
|
// B int
|
||||||
|
// }
|
||||||
|
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||||
|
// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
|
||||||
|
//
|
||||||
|
func Marshal(in interface{}) (out []byte, err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
e := newEncoder()
|
||||||
|
defer e.destroy()
|
||||||
|
e.marshalDoc("", reflect.ValueOf(in))
|
||||||
|
e.finish()
|
||||||
|
out = e.out
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Encoder writes YAML values to an output stream.
|
||||||
|
type Encoder struct {
|
||||||
|
encoder *encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a new encoder that writes to w.
|
||||||
|
// The Encoder should be closed after use to flush all data
|
||||||
|
// to w.
|
||||||
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
|
return &Encoder{
|
||||||
|
encoder: newEncoderWithWriter(w),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode writes the YAML encoding of v to the stream.
|
||||||
|
// If multiple items are encoded to the stream, the
|
||||||
|
// second and subsequent document will be preceded
|
||||||
|
// with a "---" document separator, but the first will not.
|
||||||
|
//
|
||||||
|
// See the documentation for Marshal for details about the conversion of Go
|
||||||
|
// values to YAML.
|
||||||
|
func (e *Encoder) Encode(v interface{}) (err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
e.encoder.marshalDoc("", reflect.ValueOf(v))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encodes value v and stores its representation in n.
|
||||||
|
//
|
||||||
|
// See the documentation for Marshal for details about the
|
||||||
|
// conversion of Go values into YAML.
|
||||||
|
func (n *Node) Encode(v interface{}) (err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
e := newEncoder()
|
||||||
|
defer e.destroy()
|
||||||
|
e.marshalDoc("", reflect.ValueOf(v))
|
||||||
|
e.finish()
|
||||||
|
p := newParser(e.out)
|
||||||
|
p.textless = true
|
||||||
|
defer p.destroy()
|
||||||
|
doc := p.parse()
|
||||||
|
*n = *doc.Content[0]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIndent changes the used indentation used when encoding.
|
||||||
|
func (e *Encoder) SetIndent(spaces int) {
|
||||||
|
if spaces < 0 {
|
||||||
|
panic("yaml: cannot indent to a negative number of spaces")
|
||||||
|
}
|
||||||
|
e.encoder.indent = spaces
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the encoder by writing any remaining data.
|
||||||
|
// It does not write a stream terminating string "...".
|
||||||
|
func (e *Encoder) Close() (err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
e.encoder.finish()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleErr(err *error) {
|
||||||
|
if v := recover(); v != nil {
|
||||||
|
if e, ok := v.(yamlError); ok {
|
||||||
|
*err = e.err
|
||||||
|
} else {
|
||||||
|
panic(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type yamlError struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func fail(err error) {
|
||||||
|
panic(yamlError{err})
|
||||||
|
}
|
||||||
|
|
||||||
|
func failf(format string, args ...interface{}) {
|
||||||
|
panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TypeError is returned by Unmarshal when one or more fields in
|
||||||
|
// the YAML document cannot be properly decoded into the requested
|
||||||
|
// types. When this error is returned, the value is still
|
||||||
|
// unmarshaled partially.
|
||||||
|
type TypeError struct {
|
||||||
|
Errors []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *TypeError) Error() string {
|
||||||
|
return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Kind uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
DocumentNode Kind = 1 << iota
|
||||||
|
SequenceNode
|
||||||
|
MappingNode
|
||||||
|
ScalarNode
|
||||||
|
AliasNode
|
||||||
|
)
|
||||||
|
|
||||||
|
type Style uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
TaggedStyle Style = 1 << iota
|
||||||
|
DoubleQuotedStyle
|
||||||
|
SingleQuotedStyle
|
||||||
|
LiteralStyle
|
||||||
|
FoldedStyle
|
||||||
|
FlowStyle
|
||||||
|
)
|
||||||
|
|
||||||
|
// Node represents an element in the YAML document hierarchy. While documents
|
||||||
|
// are typically encoded and decoded into higher level types, such as structs
|
||||||
|
// and maps, Node is an intermediate representation that allows detailed
|
||||||
|
// control over the content being decoded or encoded.
|
||||||
|
//
|
||||||
|
// It's worth noting that although Node offers access into details such as
|
||||||
|
// line numbers, colums, and comments, the content when re-encoded will not
|
||||||
|
// have its original textual representation preserved. An effort is made to
|
||||||
|
// render the data plesantly, and to preserve comments near the data they
|
||||||
|
// describe, though.
|
||||||
|
//
|
||||||
|
// Values that make use of the Node type interact with the yaml package in the
|
||||||
|
// same way any other type would do, by encoding and decoding yaml data
|
||||||
|
// directly or indirectly into them.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// var person struct {
|
||||||
|
// Name string
|
||||||
|
// Address yaml.Node
|
||||||
|
// }
|
||||||
|
// err := yaml.Unmarshal(data, &person)
|
||||||
|
//
|
||||||
|
// Or by itself:
|
||||||
|
//
|
||||||
|
// var person Node
|
||||||
|
// err := yaml.Unmarshal(data, &person)
|
||||||
|
//
|
||||||
|
type Node struct {
|
||||||
|
// Kind defines whether the node is a document, a mapping, a sequence,
|
||||||
|
// a scalar value, or an alias to another node. The specific data type of
|
||||||
|
// scalar nodes may be obtained via the ShortTag and LongTag methods.
|
||||||
|
Kind Kind
|
||||||
|
|
||||||
|
// Style allows customizing the apperance of the node in the tree.
|
||||||
|
Style Style
|
||||||
|
|
||||||
|
// Tag holds the YAML tag defining the data type for the value.
|
||||||
|
// When decoding, this field will always be set to the resolved tag,
|
||||||
|
// even when it wasn't explicitly provided in the YAML content.
|
||||||
|
// When encoding, if this field is unset the value type will be
|
||||||
|
// implied from the node properties, and if it is set, it will only
|
||||||
|
// be serialized into the representation if TaggedStyle is used or
|
||||||
|
// the implicit tag diverges from the provided one.
|
||||||
|
Tag string
|
||||||
|
|
||||||
|
// Value holds the unescaped and unquoted represenation of the value.
|
||||||
|
Value string
|
||||||
|
|
||||||
|
// Anchor holds the anchor name for this node, which allows aliases to point to it.
|
||||||
|
Anchor string
|
||||||
|
|
||||||
|
// Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
|
||||||
|
Alias *Node
|
||||||
|
|
||||||
|
// Content holds contained nodes for documents, mappings, and sequences.
|
||||||
|
Content []*Node
|
||||||
|
|
||||||
|
// HeadComment holds any comments in the lines preceding the node and
|
||||||
|
// not separated by an empty line.
|
||||||
|
HeadComment string
|
||||||
|
|
||||||
|
// LineComment holds any comments at the end of the line where the node is in.
|
||||||
|
LineComment string
|
||||||
|
|
||||||
|
// FootComment holds any comments following the node and before empty lines.
|
||||||
|
FootComment string
|
||||||
|
|
||||||
|
// Line and Column hold the node position in the decoded YAML text.
|
||||||
|
// These fields are not respected when encoding the node.
|
||||||
|
Line int
|
||||||
|
Column int
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns whether the node has all of its fields unset.
|
||||||
|
func (n *Node) IsZero() bool {
|
||||||
|
return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
|
||||||
|
n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LongTag returns the long form of the tag that indicates the data type for
|
||||||
|
// the node. If the Tag field isn't explicitly defined, one will be computed
|
||||||
|
// based on the node properties.
|
||||||
|
func (n *Node) LongTag() string {
|
||||||
|
return longTag(n.ShortTag())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShortTag returns the short form of the YAML tag that indicates data type for
|
||||||
|
// the node. If the Tag field isn't explicitly defined, one will be computed
|
||||||
|
// based on the node properties.
|
||||||
|
func (n *Node) ShortTag() string {
|
||||||
|
if n.indicatedString() {
|
||||||
|
return strTag
|
||||||
|
}
|
||||||
|
if n.Tag == "" || n.Tag == "!" {
|
||||||
|
switch n.Kind {
|
||||||
|
case MappingNode:
|
||||||
|
return mapTag
|
||||||
|
case SequenceNode:
|
||||||
|
return seqTag
|
||||||
|
case AliasNode:
|
||||||
|
if n.Alias != nil {
|
||||||
|
return n.Alias.ShortTag()
|
||||||
|
}
|
||||||
|
case ScalarNode:
|
||||||
|
tag, _ := resolve("", n.Value)
|
||||||
|
return tag
|
||||||
|
case 0:
|
||||||
|
// Special case to make the zero value convenient.
|
||||||
|
if n.IsZero() {
|
||||||
|
return nullTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return shortTag(n.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) indicatedString() bool {
|
||||||
|
return n.Kind == ScalarNode &&
|
||||||
|
(shortTag(n.Tag) == strTag ||
|
||||||
|
(n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString is a convenience function that sets the node to a string value
|
||||||
|
// and defines its style in a pleasant way depending on its content.
|
||||||
|
func (n *Node) SetString(s string) {
|
||||||
|
n.Kind = ScalarNode
|
||||||
|
if utf8.ValidString(s) {
|
||||||
|
n.Value = s
|
||||||
|
n.Tag = strTag
|
||||||
|
} else {
|
||||||
|
n.Value = encodeBase64(s)
|
||||||
|
n.Tag = binaryTag
|
||||||
|
}
|
||||||
|
if strings.Contains(n.Value, "\n") {
|
||||||
|
n.Style = LiteralStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Maintain a mapping of keys to structure field indexes
|
||||||
|
|
||||||
|
// The code in this section was copied from mgo/bson.
|
||||||
|
|
||||||
|
// structInfo holds details for the serialization of fields of
|
||||||
|
// a given struct.
|
||||||
|
type structInfo struct {
|
||||||
|
FieldsMap map[string]fieldInfo
|
||||||
|
FieldsList []fieldInfo
|
||||||
|
|
||||||
|
// InlineMap is the number of the field in the struct that
|
||||||
|
// contains an ,inline map, or -1 if there's none.
|
||||||
|
InlineMap int
|
||||||
|
|
||||||
|
// InlineUnmarshalers holds indexes to inlined fields that
|
||||||
|
// contain unmarshaler values.
|
||||||
|
InlineUnmarshalers [][]int
|
||||||
|
}
|
||||||
|
|
||||||
|
type fieldInfo struct {
|
||||||
|
Key string
|
||||||
|
Num int
|
||||||
|
OmitEmpty bool
|
||||||
|
Flow bool
|
||||||
|
// Id holds the unique field identifier, so we can cheaply
|
||||||
|
// check for field duplicates without maintaining an extra map.
|
||||||
|
Id int
|
||||||
|
|
||||||
|
// Inline holds the field index if the field is part of an inlined struct.
|
||||||
|
Inline []int
|
||||||
|
}
|
||||||
|
|
||||||
|
var structMap = make(map[reflect.Type]*structInfo)
|
||||||
|
var fieldMapMutex sync.RWMutex
|
||||||
|
var unmarshalerType reflect.Type
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var v Unmarshaler
|
||||||
|
unmarshalerType = reflect.ValueOf(&v).Elem().Type()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getStructInfo(st reflect.Type) (*structInfo, error) {
|
||||||
|
fieldMapMutex.RLock()
|
||||||
|
sinfo, found := structMap[st]
|
||||||
|
fieldMapMutex.RUnlock()
|
||||||
|
if found {
|
||||||
|
return sinfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n := st.NumField()
|
||||||
|
fieldsMap := make(map[string]fieldInfo)
|
||||||
|
fieldsList := make([]fieldInfo, 0, n)
|
||||||
|
inlineMap := -1
|
||||||
|
inlineUnmarshalers := [][]int(nil)
|
||||||
|
for i := 0; i != n; i++ {
|
||||||
|
field := st.Field(i)
|
||||||
|
if field.PkgPath != "" && !field.Anonymous {
|
||||||
|
continue // Private field
|
||||||
|
}
|
||||||
|
|
||||||
|
info := fieldInfo{Num: i}
|
||||||
|
|
||||||
|
tag := field.Tag.Get("yaml")
|
||||||
|
if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
|
||||||
|
tag = string(field.Tag)
|
||||||
|
}
|
||||||
|
if tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inline := false
|
||||||
|
fields := strings.Split(tag, ",")
|
||||||
|
if len(fields) > 1 {
|
||||||
|
for _, flag := range fields[1:] {
|
||||||
|
switch flag {
|
||||||
|
case "omitempty":
|
||||||
|
info.OmitEmpty = true
|
||||||
|
case "flow":
|
||||||
|
info.Flow = true
|
||||||
|
case "inline":
|
||||||
|
inline = true
|
||||||
|
default:
|
||||||
|
return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tag = fields[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if inline {
|
||||||
|
switch field.Type.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
if inlineMap >= 0 {
|
||||||
|
return nil, errors.New("multiple ,inline maps in struct " + st.String())
|
||||||
|
}
|
||||||
|
if field.Type.Key() != reflect.TypeOf("") {
|
||||||
|
return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
|
||||||
|
}
|
||||||
|
inlineMap = info.Num
|
||||||
|
case reflect.Struct, reflect.Ptr:
|
||||||
|
ftype := field.Type
|
||||||
|
for ftype.Kind() == reflect.Ptr {
|
||||||
|
ftype = ftype.Elem()
|
||||||
|
}
|
||||||
|
if ftype.Kind() != reflect.Struct {
|
||||||
|
return nil, errors.New("option ,inline may only be used on a struct or map field")
|
||||||
|
}
|
||||||
|
if reflect.PtrTo(ftype).Implements(unmarshalerType) {
|
||||||
|
inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
|
||||||
|
} else {
|
||||||
|
sinfo, err := getStructInfo(ftype)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, index := range sinfo.InlineUnmarshalers {
|
||||||
|
inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
|
||||||
|
}
|
||||||
|
for _, finfo := range sinfo.FieldsList {
|
||||||
|
if _, found := fieldsMap[finfo.Key]; found {
|
||||||
|
msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
|
||||||
|
return nil, errors.New(msg)
|
||||||
|
}
|
||||||
|
if finfo.Inline == nil {
|
||||||
|
finfo.Inline = []int{i, finfo.Num}
|
||||||
|
} else {
|
||||||
|
finfo.Inline = append([]int{i}, finfo.Inline...)
|
||||||
|
}
|
||||||
|
finfo.Id = len(fieldsList)
|
||||||
|
fieldsMap[finfo.Key] = finfo
|
||||||
|
fieldsList = append(fieldsList, finfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, errors.New("option ,inline may only be used on a struct or map field")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag != "" {
|
||||||
|
info.Key = tag
|
||||||
|
} else {
|
||||||
|
info.Key = strings.ToLower(field.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, found = fieldsMap[info.Key]; found {
|
||||||
|
msg := "duplicated key '" + info.Key + "' in struct " + st.String()
|
||||||
|
return nil, errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
info.Id = len(fieldsList)
|
||||||
|
fieldsList = append(fieldsList, info)
|
||||||
|
fieldsMap[info.Key] = info
|
||||||
|
}
|
||||||
|
|
||||||
|
sinfo = &structInfo{
|
||||||
|
FieldsMap: fieldsMap,
|
||||||
|
FieldsList: fieldsList,
|
||||||
|
InlineMap: inlineMap,
|
||||||
|
InlineUnmarshalers: inlineUnmarshalers,
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldMapMutex.Lock()
|
||||||
|
structMap[st] = sinfo
|
||||||
|
fieldMapMutex.Unlock()
|
||||||
|
return sinfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZeroer is used to check whether an object is zero to
|
||||||
|
// determine whether it should be omitted when marshaling
|
||||||
|
// with the omitempty flag. One notable implementation
|
||||||
|
// is time.Time.
|
||||||
|
type IsZeroer interface {
|
||||||
|
IsZero() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func isZero(v reflect.Value) bool {
|
||||||
|
kind := v.Kind()
|
||||||
|
if z, ok := v.Interface().(IsZeroer); ok {
|
||||||
|
if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return z.IsZero()
|
||||||
|
}
|
||||||
|
switch kind {
|
||||||
|
case reflect.String:
|
||||||
|
return len(v.String()) == 0
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
return v.IsNil()
|
||||||
|
case reflect.Slice:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Map:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case reflect.Struct:
|
||||||
|
vt := v.Type()
|
||||||
|
for i := v.NumField() - 1; i >= 0; i-- {
|
||||||
|
if vt.Field(i).PkgPath != "" {
|
||||||
|
continue // Private field
|
||||||
|
}
|
||||||
|
if !isZero(v.Field(i)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
807
vendor/gopkg.in/yaml.v3/yamlh.go
generated
vendored
Normal file
807
vendor/gopkg.in/yaml.v3/yamlh.go
generated
vendored
Normal file
|
@ -0,0 +1,807 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2019 Canonical Ltd
|
||||||
|
// Copyright (c) 2006-2010 Kirill Simonov
|
||||||
|
//
|
||||||
|
// 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 yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The version directive data.
|
||||||
|
type yaml_version_directive_t struct {
|
||||||
|
major int8 // The major version number.
|
||||||
|
minor int8 // The minor version number.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tag directive data.
|
||||||
|
type yaml_tag_directive_t struct {
|
||||||
|
handle []byte // The tag handle.
|
||||||
|
prefix []byte // The tag prefix.
|
||||||
|
}
|
||||||
|
|
||||||
|
type yaml_encoding_t int
|
||||||
|
|
||||||
|
// The stream encoding.
|
||||||
|
const (
|
||||||
|
// Let the parser choose the encoding.
|
||||||
|
yaml_ANY_ENCODING yaml_encoding_t = iota
|
||||||
|
|
||||||
|
yaml_UTF8_ENCODING // The default UTF-8 encoding.
|
||||||
|
yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
|
||||||
|
yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_break_t int
|
||||||
|
|
||||||
|
// Line break types.
|
||||||
|
const (
|
||||||
|
// Let the parser choose the break type.
|
||||||
|
yaml_ANY_BREAK yaml_break_t = iota
|
||||||
|
|
||||||
|
yaml_CR_BREAK // Use CR for line breaks (Mac style).
|
||||||
|
yaml_LN_BREAK // Use LN for line breaks (Unix style).
|
||||||
|
yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_error_type_t int
|
||||||
|
|
||||||
|
// Many bad things could happen with the parser and emitter.
|
||||||
|
const (
|
||||||
|
// No error is produced.
|
||||||
|
yaml_NO_ERROR yaml_error_type_t = iota
|
||||||
|
|
||||||
|
yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory.
|
||||||
|
yaml_READER_ERROR // Cannot read or decode the input stream.
|
||||||
|
yaml_SCANNER_ERROR // Cannot scan the input stream.
|
||||||
|
yaml_PARSER_ERROR // Cannot parse the input stream.
|
||||||
|
yaml_COMPOSER_ERROR // Cannot compose a YAML document.
|
||||||
|
yaml_WRITER_ERROR // Cannot write to the output stream.
|
||||||
|
yaml_EMITTER_ERROR // Cannot emit a YAML stream.
|
||||||
|
)
|
||||||
|
|
||||||
|
// The pointer position.
|
||||||
|
type yaml_mark_t struct {
|
||||||
|
index int // The position index.
|
||||||
|
line int // The position line.
|
||||||
|
column int // The position column.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node Styles
|
||||||
|
|
||||||
|
type yaml_style_t int8
|
||||||
|
|
||||||
|
type yaml_scalar_style_t yaml_style_t
|
||||||
|
|
||||||
|
// Scalar styles.
|
||||||
|
const (
|
||||||
|
// Let the emitter choose the style.
|
||||||
|
yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0
|
||||||
|
|
||||||
|
yaml_PLAIN_SCALAR_STYLE yaml_scalar_style_t = 1 << iota // The plain scalar style.
|
||||||
|
yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
|
||||||
|
yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
|
||||||
|
yaml_LITERAL_SCALAR_STYLE // The literal scalar style.
|
||||||
|
yaml_FOLDED_SCALAR_STYLE // The folded scalar style.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_sequence_style_t yaml_style_t
|
||||||
|
|
||||||
|
// Sequence styles.
|
||||||
|
const (
|
||||||
|
// Let the emitter choose the style.
|
||||||
|
yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
|
||||||
|
|
||||||
|
yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
|
||||||
|
yaml_FLOW_SEQUENCE_STYLE // The flow sequence style.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_mapping_style_t yaml_style_t
|
||||||
|
|
||||||
|
// Mapping styles.
|
||||||
|
const (
|
||||||
|
// Let the emitter choose the style.
|
||||||
|
yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
|
||||||
|
|
||||||
|
yaml_BLOCK_MAPPING_STYLE // The block mapping style.
|
||||||
|
yaml_FLOW_MAPPING_STYLE // The flow mapping style.
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tokens
|
||||||
|
|
||||||
|
type yaml_token_type_t int
|
||||||
|
|
||||||
|
// Token types.
|
||||||
|
const (
|
||||||
|
// An empty token.
|
||||||
|
yaml_NO_TOKEN yaml_token_type_t = iota
|
||||||
|
|
||||||
|
yaml_STREAM_START_TOKEN // A STREAM-START token.
|
||||||
|
yaml_STREAM_END_TOKEN // A STREAM-END token.
|
||||||
|
|
||||||
|
yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
|
||||||
|
yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token.
|
||||||
|
yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token.
|
||||||
|
yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token.
|
||||||
|
|
||||||
|
yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
|
||||||
|
yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token.
|
||||||
|
yaml_BLOCK_END_TOKEN // A BLOCK-END token.
|
||||||
|
|
||||||
|
yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
|
||||||
|
yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token.
|
||||||
|
yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token.
|
||||||
|
yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token.
|
||||||
|
|
||||||
|
yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
|
||||||
|
yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token.
|
||||||
|
yaml_KEY_TOKEN // A KEY token.
|
||||||
|
yaml_VALUE_TOKEN // A VALUE token.
|
||||||
|
|
||||||
|
yaml_ALIAS_TOKEN // An ALIAS token.
|
||||||
|
yaml_ANCHOR_TOKEN // An ANCHOR token.
|
||||||
|
yaml_TAG_TOKEN // A TAG token.
|
||||||
|
yaml_SCALAR_TOKEN // A SCALAR token.
|
||||||
|
)
|
||||||
|
|
||||||
|
func (tt yaml_token_type_t) String() string {
|
||||||
|
switch tt {
|
||||||
|
case yaml_NO_TOKEN:
|
||||||
|
return "yaml_NO_TOKEN"
|
||||||
|
case yaml_STREAM_START_TOKEN:
|
||||||
|
return "yaml_STREAM_START_TOKEN"
|
||||||
|
case yaml_STREAM_END_TOKEN:
|
||||||
|
return "yaml_STREAM_END_TOKEN"
|
||||||
|
case yaml_VERSION_DIRECTIVE_TOKEN:
|
||||||
|
return "yaml_VERSION_DIRECTIVE_TOKEN"
|
||||||
|
case yaml_TAG_DIRECTIVE_TOKEN:
|
||||||
|
return "yaml_TAG_DIRECTIVE_TOKEN"
|
||||||
|
case yaml_DOCUMENT_START_TOKEN:
|
||||||
|
return "yaml_DOCUMENT_START_TOKEN"
|
||||||
|
case yaml_DOCUMENT_END_TOKEN:
|
||||||
|
return "yaml_DOCUMENT_END_TOKEN"
|
||||||
|
case yaml_BLOCK_SEQUENCE_START_TOKEN:
|
||||||
|
return "yaml_BLOCK_SEQUENCE_START_TOKEN"
|
||||||
|
case yaml_BLOCK_MAPPING_START_TOKEN:
|
||||||
|
return "yaml_BLOCK_MAPPING_START_TOKEN"
|
||||||
|
case yaml_BLOCK_END_TOKEN:
|
||||||
|
return "yaml_BLOCK_END_TOKEN"
|
||||||
|
case yaml_FLOW_SEQUENCE_START_TOKEN:
|
||||||
|
return "yaml_FLOW_SEQUENCE_START_TOKEN"
|
||||||
|
case yaml_FLOW_SEQUENCE_END_TOKEN:
|
||||||
|
return "yaml_FLOW_SEQUENCE_END_TOKEN"
|
||||||
|
case yaml_FLOW_MAPPING_START_TOKEN:
|
||||||
|
return "yaml_FLOW_MAPPING_START_TOKEN"
|
||||||
|
case yaml_FLOW_MAPPING_END_TOKEN:
|
||||||
|
return "yaml_FLOW_MAPPING_END_TOKEN"
|
||||||
|
case yaml_BLOCK_ENTRY_TOKEN:
|
||||||
|
return "yaml_BLOCK_ENTRY_TOKEN"
|
||||||
|
case yaml_FLOW_ENTRY_TOKEN:
|
||||||
|
return "yaml_FLOW_ENTRY_TOKEN"
|
||||||
|
case yaml_KEY_TOKEN:
|
||||||
|
return "yaml_KEY_TOKEN"
|
||||||
|
case yaml_VALUE_TOKEN:
|
||||||
|
return "yaml_VALUE_TOKEN"
|
||||||
|
case yaml_ALIAS_TOKEN:
|
||||||
|
return "yaml_ALIAS_TOKEN"
|
||||||
|
case yaml_ANCHOR_TOKEN:
|
||||||
|
return "yaml_ANCHOR_TOKEN"
|
||||||
|
case yaml_TAG_TOKEN:
|
||||||
|
return "yaml_TAG_TOKEN"
|
||||||
|
case yaml_SCALAR_TOKEN:
|
||||||
|
return "yaml_SCALAR_TOKEN"
|
||||||
|
}
|
||||||
|
return "<unknown token>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// The token structure.
|
||||||
|
type yaml_token_t struct {
|
||||||
|
// The token type.
|
||||||
|
typ yaml_token_type_t
|
||||||
|
|
||||||
|
// The start/end of the token.
|
||||||
|
start_mark, end_mark yaml_mark_t
|
||||||
|
|
||||||
|
// The stream encoding (for yaml_STREAM_START_TOKEN).
|
||||||
|
encoding yaml_encoding_t
|
||||||
|
|
||||||
|
// The alias/anchor/scalar value or tag/tag directive handle
|
||||||
|
// (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
|
||||||
|
value []byte
|
||||||
|
|
||||||
|
// The tag suffix (for yaml_TAG_TOKEN).
|
||||||
|
suffix []byte
|
||||||
|
|
||||||
|
// The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
|
||||||
|
prefix []byte
|
||||||
|
|
||||||
|
// The scalar style (for yaml_SCALAR_TOKEN).
|
||||||
|
style yaml_scalar_style_t
|
||||||
|
|
||||||
|
// The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
|
||||||
|
major, minor int8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
|
||||||
|
type yaml_event_type_t int8
|
||||||
|
|
||||||
|
// Event types.
|
||||||
|
const (
|
||||||
|
// An empty event.
|
||||||
|
yaml_NO_EVENT yaml_event_type_t = iota
|
||||||
|
|
||||||
|
yaml_STREAM_START_EVENT // A STREAM-START event.
|
||||||
|
yaml_STREAM_END_EVENT // A STREAM-END event.
|
||||||
|
yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
|
||||||
|
yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event.
|
||||||
|
yaml_ALIAS_EVENT // An ALIAS event.
|
||||||
|
yaml_SCALAR_EVENT // A SCALAR event.
|
||||||
|
yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
|
||||||
|
yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event.
|
||||||
|
yaml_MAPPING_START_EVENT // A MAPPING-START event.
|
||||||
|
yaml_MAPPING_END_EVENT // A MAPPING-END event.
|
||||||
|
yaml_TAIL_COMMENT_EVENT
|
||||||
|
)
|
||||||
|
|
||||||
|
var eventStrings = []string{
|
||||||
|
yaml_NO_EVENT: "none",
|
||||||
|
yaml_STREAM_START_EVENT: "stream start",
|
||||||
|
yaml_STREAM_END_EVENT: "stream end",
|
||||||
|
yaml_DOCUMENT_START_EVENT: "document start",
|
||||||
|
yaml_DOCUMENT_END_EVENT: "document end",
|
||||||
|
yaml_ALIAS_EVENT: "alias",
|
||||||
|
yaml_SCALAR_EVENT: "scalar",
|
||||||
|
yaml_SEQUENCE_START_EVENT: "sequence start",
|
||||||
|
yaml_SEQUENCE_END_EVENT: "sequence end",
|
||||||
|
yaml_MAPPING_START_EVENT: "mapping start",
|
||||||
|
yaml_MAPPING_END_EVENT: "mapping end",
|
||||||
|
yaml_TAIL_COMMENT_EVENT: "tail comment",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e yaml_event_type_t) String() string {
|
||||||
|
if e < 0 || int(e) >= len(eventStrings) {
|
||||||
|
return fmt.Sprintf("unknown event %d", e)
|
||||||
|
}
|
||||||
|
return eventStrings[e]
|
||||||
|
}
|
||||||
|
|
||||||
|
// The event structure.
|
||||||
|
type yaml_event_t struct {
|
||||||
|
|
||||||
|
// The event type.
|
||||||
|
typ yaml_event_type_t
|
||||||
|
|
||||||
|
// The start and end of the event.
|
||||||
|
start_mark, end_mark yaml_mark_t
|
||||||
|
|
||||||
|
// The document encoding (for yaml_STREAM_START_EVENT).
|
||||||
|
encoding yaml_encoding_t
|
||||||
|
|
||||||
|
// The version directive (for yaml_DOCUMENT_START_EVENT).
|
||||||
|
version_directive *yaml_version_directive_t
|
||||||
|
|
||||||
|
// The list of tag directives (for yaml_DOCUMENT_START_EVENT).
|
||||||
|
tag_directives []yaml_tag_directive_t
|
||||||
|
|
||||||
|
// The comments
|
||||||
|
head_comment []byte
|
||||||
|
line_comment []byte
|
||||||
|
foot_comment []byte
|
||||||
|
tail_comment []byte
|
||||||
|
|
||||||
|
// The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
|
||||||
|
anchor []byte
|
||||||
|
|
||||||
|
// The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
|
||||||
|
tag []byte
|
||||||
|
|
||||||
|
// The scalar value (for yaml_SCALAR_EVENT).
|
||||||
|
value []byte
|
||||||
|
|
||||||
|
// Is the document start/end indicator implicit, or the tag optional?
|
||||||
|
// (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
|
||||||
|
implicit bool
|
||||||
|
|
||||||
|
// Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
|
||||||
|
quoted_implicit bool
|
||||||
|
|
||||||
|
// The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
|
||||||
|
style yaml_style_t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) }
|
||||||
|
func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
|
||||||
|
func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) }
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
|
||||||
|
const (
|
||||||
|
yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null.
|
||||||
|
yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false.
|
||||||
|
yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values.
|
||||||
|
yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values.
|
||||||
|
yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values.
|
||||||
|
yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
|
||||||
|
|
||||||
|
yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
|
||||||
|
yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
|
||||||
|
|
||||||
|
// Not in original libyaml.
|
||||||
|
yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
|
||||||
|
yaml_MERGE_TAG = "tag:yaml.org,2002:merge"
|
||||||
|
|
||||||
|
yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str.
|
||||||
|
yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
|
||||||
|
yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_node_type_t int
|
||||||
|
|
||||||
|
// Node types.
|
||||||
|
const (
|
||||||
|
// An empty node.
|
||||||
|
yaml_NO_NODE yaml_node_type_t = iota
|
||||||
|
|
||||||
|
yaml_SCALAR_NODE // A scalar node.
|
||||||
|
yaml_SEQUENCE_NODE // A sequence node.
|
||||||
|
yaml_MAPPING_NODE // A mapping node.
|
||||||
|
)
|
||||||
|
|
||||||
|
// An element of a sequence node.
|
||||||
|
type yaml_node_item_t int
|
||||||
|
|
||||||
|
// An element of a mapping node.
|
||||||
|
type yaml_node_pair_t struct {
|
||||||
|
key int // The key of the element.
|
||||||
|
value int // The value of the element.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The node structure.
|
||||||
|
type yaml_node_t struct {
|
||||||
|
typ yaml_node_type_t // The node type.
|
||||||
|
tag []byte // The node tag.
|
||||||
|
|
||||||
|
// The node data.
|
||||||
|
|
||||||
|
// The scalar parameters (for yaml_SCALAR_NODE).
|
||||||
|
scalar struct {
|
||||||
|
value []byte // The scalar value.
|
||||||
|
length int // The length of the scalar value.
|
||||||
|
style yaml_scalar_style_t // The scalar style.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The sequence parameters (for YAML_SEQUENCE_NODE).
|
||||||
|
sequence struct {
|
||||||
|
items_data []yaml_node_item_t // The stack of sequence items.
|
||||||
|
style yaml_sequence_style_t // The sequence style.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The mapping parameters (for yaml_MAPPING_NODE).
|
||||||
|
mapping struct {
|
||||||
|
pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value).
|
||||||
|
pairs_start *yaml_node_pair_t // The beginning of the stack.
|
||||||
|
pairs_end *yaml_node_pair_t // The end of the stack.
|
||||||
|
pairs_top *yaml_node_pair_t // The top of the stack.
|
||||||
|
style yaml_mapping_style_t // The mapping style.
|
||||||
|
}
|
||||||
|
|
||||||
|
start_mark yaml_mark_t // The beginning of the node.
|
||||||
|
end_mark yaml_mark_t // The end of the node.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// The document structure.
|
||||||
|
type yaml_document_t struct {
|
||||||
|
|
||||||
|
// The document nodes.
|
||||||
|
nodes []yaml_node_t
|
||||||
|
|
||||||
|
// The version directive.
|
||||||
|
version_directive *yaml_version_directive_t
|
||||||
|
|
||||||
|
// The list of tag directives.
|
||||||
|
tag_directives_data []yaml_tag_directive_t
|
||||||
|
tag_directives_start int // The beginning of the tag directives list.
|
||||||
|
tag_directives_end int // The end of the tag directives list.
|
||||||
|
|
||||||
|
start_implicit int // Is the document start indicator implicit?
|
||||||
|
end_implicit int // Is the document end indicator implicit?
|
||||||
|
|
||||||
|
// The start/end of the document.
|
||||||
|
start_mark, end_mark yaml_mark_t
|
||||||
|
}
|
||||||
|
|
||||||
|
// The prototype of a read handler.
|
||||||
|
//
|
||||||
|
// The read handler is called when the parser needs to read more bytes from the
|
||||||
|
// source. The handler should write not more than size bytes to the buffer.
|
||||||
|
// The number of written bytes should be set to the size_read variable.
|
||||||
|
//
|
||||||
|
// [in,out] data A pointer to an application data specified by
|
||||||
|
// yaml_parser_set_input().
|
||||||
|
// [out] buffer The buffer to write the data from the source.
|
||||||
|
// [in] size The size of the buffer.
|
||||||
|
// [out] size_read The actual number of bytes read from the source.
|
||||||
|
//
|
||||||
|
// On success, the handler should return 1. If the handler failed,
|
||||||
|
// the returned value should be 0. On EOF, the handler should set the
|
||||||
|
// size_read to 0 and return 1.
|
||||||
|
type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
|
||||||
|
|
||||||
|
// This structure holds information about a potential simple key.
|
||||||
|
type yaml_simple_key_t struct {
|
||||||
|
possible bool // Is a simple key possible?
|
||||||
|
required bool // Is a simple key required?
|
||||||
|
token_number int // The number of the token.
|
||||||
|
mark yaml_mark_t // The position mark.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The states of the parser.
|
||||||
|
type yaml_parser_state_t int
|
||||||
|
|
||||||
|
const (
|
||||||
|
yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
|
||||||
|
|
||||||
|
yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document.
|
||||||
|
yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START.
|
||||||
|
yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document.
|
||||||
|
yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END.
|
||||||
|
yaml_PARSE_BLOCK_NODE_STATE // Expect a block node.
|
||||||
|
yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
|
||||||
|
yaml_PARSE_FLOW_NODE_STATE // Expect a flow node.
|
||||||
|
yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence.
|
||||||
|
yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence.
|
||||||
|
yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence.
|
||||||
|
yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
|
||||||
|
yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key.
|
||||||
|
yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping.
|
||||||
|
yaml_PARSE_END_STATE // Expect nothing.
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ps yaml_parser_state_t) String() string {
|
||||||
|
switch ps {
|
||||||
|
case yaml_PARSE_STREAM_START_STATE:
|
||||||
|
return "yaml_PARSE_STREAM_START_STATE"
|
||||||
|
case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
|
||||||
|
return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
|
||||||
|
case yaml_PARSE_DOCUMENT_START_STATE:
|
||||||
|
return "yaml_PARSE_DOCUMENT_START_STATE"
|
||||||
|
case yaml_PARSE_DOCUMENT_CONTENT_STATE:
|
||||||
|
return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
|
||||||
|
case yaml_PARSE_DOCUMENT_END_STATE:
|
||||||
|
return "yaml_PARSE_DOCUMENT_END_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_NODE_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_NODE_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_NODE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_NODE_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
|
||||||
|
case yaml_PARSE_END_STATE:
|
||||||
|
return "yaml_PARSE_END_STATE"
|
||||||
|
}
|
||||||
|
return "<unknown parser state>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// This structure holds aliases data.
|
||||||
|
type yaml_alias_data_t struct {
|
||||||
|
anchor []byte // The anchor.
|
||||||
|
index int // The node id.
|
||||||
|
mark yaml_mark_t // The anchor mark.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The parser structure.
|
||||||
|
//
|
||||||
|
// All members are internal. Manage the structure using the
|
||||||
|
// yaml_parser_ family of functions.
|
||||||
|
type yaml_parser_t struct {
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
|
||||||
|
error yaml_error_type_t // Error type.
|
||||||
|
|
||||||
|
problem string // Error description.
|
||||||
|
|
||||||
|
// The byte about which the problem occurred.
|
||||||
|
problem_offset int
|
||||||
|
problem_value int
|
||||||
|
problem_mark yaml_mark_t
|
||||||
|
|
||||||
|
// The error context.
|
||||||
|
context string
|
||||||
|
context_mark yaml_mark_t
|
||||||
|
|
||||||
|
// Reader stuff
|
||||||
|
|
||||||
|
read_handler yaml_read_handler_t // Read handler.
|
||||||
|
|
||||||
|
input_reader io.Reader // File input data.
|
||||||
|
input []byte // String input data.
|
||||||
|
input_pos int
|
||||||
|
|
||||||
|
eof bool // EOF flag
|
||||||
|
|
||||||
|
buffer []byte // The working buffer.
|
||||||
|
buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
unread int // The number of unread characters in the buffer.
|
||||||
|
|
||||||
|
newlines int // The number of line breaks since last non-break/non-blank character
|
||||||
|
|
||||||
|
raw_buffer []byte // The raw buffer.
|
||||||
|
raw_buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
encoding yaml_encoding_t // The input encoding.
|
||||||
|
|
||||||
|
offset int // The offset of the current position (in bytes).
|
||||||
|
mark yaml_mark_t // The mark of the current position.
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
|
||||||
|
head_comment []byte // The current head comments
|
||||||
|
line_comment []byte // The current line comments
|
||||||
|
foot_comment []byte // The current foot comments
|
||||||
|
tail_comment []byte // Foot comment that happens at the end of a block.
|
||||||
|
stem_comment []byte // Comment in item preceding a nested structure (list inside list item, etc)
|
||||||
|
|
||||||
|
comments []yaml_comment_t // The folded comments for all parsed tokens
|
||||||
|
comments_head int
|
||||||
|
|
||||||
|
// Scanner stuff
|
||||||
|
|
||||||
|
stream_start_produced bool // Have we started to scan the input stream?
|
||||||
|
stream_end_produced bool // Have we reached the end of the input stream?
|
||||||
|
|
||||||
|
flow_level int // The number of unclosed '[' and '{' indicators.
|
||||||
|
|
||||||
|
tokens []yaml_token_t // The tokens queue.
|
||||||
|
tokens_head int // The head of the tokens queue.
|
||||||
|
tokens_parsed int // The number of tokens fetched from the queue.
|
||||||
|
token_available bool // Does the tokens queue contain a token ready for dequeueing.
|
||||||
|
|
||||||
|
indent int // The current indentation level.
|
||||||
|
indents []int // The indentation levels stack.
|
||||||
|
|
||||||
|
simple_key_allowed bool // May a simple key occur at the current position?
|
||||||
|
simple_keys []yaml_simple_key_t // The stack of simple keys.
|
||||||
|
simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
|
||||||
|
|
||||||
|
// Parser stuff
|
||||||
|
|
||||||
|
state yaml_parser_state_t // The current parser state.
|
||||||
|
states []yaml_parser_state_t // The parser states stack.
|
||||||
|
marks []yaml_mark_t // The stack of marks.
|
||||||
|
tag_directives []yaml_tag_directive_t // The list of TAG directives.
|
||||||
|
|
||||||
|
// Dumper stuff
|
||||||
|
|
||||||
|
aliases []yaml_alias_data_t // The alias data.
|
||||||
|
|
||||||
|
document *yaml_document_t // The currently parsed document.
|
||||||
|
}
|
||||||
|
|
||||||
|
type yaml_comment_t struct {
|
||||||
|
|
||||||
|
scan_mark yaml_mark_t // Position where scanning for comments started
|
||||||
|
token_mark yaml_mark_t // Position after which tokens will be associated with this comment
|
||||||
|
start_mark yaml_mark_t // Position of '#' comment mark
|
||||||
|
end_mark yaml_mark_t // Position where comment terminated
|
||||||
|
|
||||||
|
head []byte
|
||||||
|
line []byte
|
||||||
|
foot []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emitter Definitions
|
||||||
|
|
||||||
|
// The prototype of a write handler.
|
||||||
|
//
|
||||||
|
// The write handler is called when the emitter needs to flush the accumulated
|
||||||
|
// characters to the output. The handler should write @a size bytes of the
|
||||||
|
// @a buffer to the output.
|
||||||
|
//
|
||||||
|
// @param[in,out] data A pointer to an application data specified by
|
||||||
|
// yaml_emitter_set_output().
|
||||||
|
// @param[in] buffer The buffer with bytes to be written.
|
||||||
|
// @param[in] size The size of the buffer.
|
||||||
|
//
|
||||||
|
// @returns On success, the handler should return @c 1. If the handler failed,
|
||||||
|
// the returned value should be @c 0.
|
||||||
|
//
|
||||||
|
type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
|
||||||
|
|
||||||
|
type yaml_emitter_state_t int
|
||||||
|
|
||||||
|
// The emitter states.
|
||||||
|
const (
|
||||||
|
// Expect STREAM-START.
|
||||||
|
yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
|
||||||
|
|
||||||
|
yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END.
|
||||||
|
yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END.
|
||||||
|
yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document.
|
||||||
|
yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END.
|
||||||
|
yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence.
|
||||||
|
yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE // Expect the next item of a flow sequence, with the comma already written out
|
||||||
|
yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE // Expect the next key of a flow mapping, with the comma already written out
|
||||||
|
yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
|
||||||
|
yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence.
|
||||||
|
yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping.
|
||||||
|
yaml_EMIT_END_STATE // Expect nothing.
|
||||||
|
)
|
||||||
|
|
||||||
|
// The emitter structure.
|
||||||
|
//
|
||||||
|
// All members are internal. Manage the structure using the @c yaml_emitter_
|
||||||
|
// family of functions.
|
||||||
|
type yaml_emitter_t struct {
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
|
||||||
|
error yaml_error_type_t // Error type.
|
||||||
|
problem string // Error description.
|
||||||
|
|
||||||
|
// Writer stuff
|
||||||
|
|
||||||
|
write_handler yaml_write_handler_t // Write handler.
|
||||||
|
|
||||||
|
output_buffer *[]byte // String output data.
|
||||||
|
output_writer io.Writer // File output data.
|
||||||
|
|
||||||
|
buffer []byte // The working buffer.
|
||||||
|
buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
raw_buffer []byte // The raw buffer.
|
||||||
|
raw_buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
encoding yaml_encoding_t // The stream encoding.
|
||||||
|
|
||||||
|
// Emitter stuff
|
||||||
|
|
||||||
|
canonical bool // If the output is in the canonical style?
|
||||||
|
best_indent int // The number of indentation spaces.
|
||||||
|
best_width int // The preferred width of the output lines.
|
||||||
|
unicode bool // Allow unescaped non-ASCII characters?
|
||||||
|
line_break yaml_break_t // The preferred line break.
|
||||||
|
|
||||||
|
state yaml_emitter_state_t // The current emitter state.
|
||||||
|
states []yaml_emitter_state_t // The stack of states.
|
||||||
|
|
||||||
|
events []yaml_event_t // The event queue.
|
||||||
|
events_head int // The head of the event queue.
|
||||||
|
|
||||||
|
indents []int // The stack of indentation levels.
|
||||||
|
|
||||||
|
tag_directives []yaml_tag_directive_t // The list of tag directives.
|
||||||
|
|
||||||
|
indent int // The current indentation level.
|
||||||
|
|
||||||
|
flow_level int // The current flow level.
|
||||||
|
|
||||||
|
root_context bool // Is it the document root context?
|
||||||
|
sequence_context bool // Is it a sequence context?
|
||||||
|
mapping_context bool // Is it a mapping context?
|
||||||
|
simple_key_context bool // Is it a simple mapping key context?
|
||||||
|
|
||||||
|
line int // The current line.
|
||||||
|
column int // The current column.
|
||||||
|
whitespace bool // If the last character was a whitespace?
|
||||||
|
indention bool // If the last character was an indentation character (' ', '-', '?', ':')?
|
||||||
|
open_ended bool // If an explicit document end is required?
|
||||||
|
|
||||||
|
space_above bool // Is there's an empty line above?
|
||||||
|
foot_indent int // The indent used to write the foot comment above, or -1 if none.
|
||||||
|
|
||||||
|
// Anchor analysis.
|
||||||
|
anchor_data struct {
|
||||||
|
anchor []byte // The anchor value.
|
||||||
|
alias bool // Is it an alias?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag analysis.
|
||||||
|
tag_data struct {
|
||||||
|
handle []byte // The tag handle.
|
||||||
|
suffix []byte // The tag suffix.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scalar analysis.
|
||||||
|
scalar_data struct {
|
||||||
|
value []byte // The scalar value.
|
||||||
|
multiline bool // Does the scalar contain line breaks?
|
||||||
|
flow_plain_allowed bool // Can the scalar be expessed in the flow plain style?
|
||||||
|
block_plain_allowed bool // Can the scalar be expressed in the block plain style?
|
||||||
|
single_quoted_allowed bool // Can the scalar be expressed in the single quoted style?
|
||||||
|
block_allowed bool // Can the scalar be expressed in the literal or folded styles?
|
||||||
|
style yaml_scalar_style_t // The output style.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
head_comment []byte
|
||||||
|
line_comment []byte
|
||||||
|
foot_comment []byte
|
||||||
|
tail_comment []byte
|
||||||
|
|
||||||
|
key_line_comment []byte
|
||||||
|
|
||||||
|
// Dumper stuff
|
||||||
|
|
||||||
|
opened bool // If the stream was already opened?
|
||||||
|
closed bool // If the stream was already closed?
|
||||||
|
|
||||||
|
// The information associated with the document nodes.
|
||||||
|
anchors *struct {
|
||||||
|
references int // The number of references.
|
||||||
|
anchor int // The anchor id.
|
||||||
|
serialized bool // If the node has been emitted?
|
||||||
|
}
|
||||||
|
|
||||||
|
last_anchor_id int // The last assigned anchor id.
|
||||||
|
|
||||||
|
document *yaml_document_t // The currently emitted document.
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue