cmd/geth: add --config file flag (#13875)
* p2p/discover, p2p/discv5: add marshaling methods to Node * p2p/netutil: make Netlist decodable from TOML * common/math: encode nil HexOrDecimal256 as 0x0 * cmd/geth: add --config file flag * cmd/geth: add missing license header * eth: prettify Config again, fix tests * eth: use gasprice.Config instead of duplicating its fields * eth/gasprice: hide nil default from dumpconfig output * cmd/geth: hide genesis block in dumpconfig output * node: make tests compile * console: fix tests * cmd/geth: make TOML keys look exactly like Go struct fields * p2p: use discovery by default This makes the zero Config slightly more useful. It also fixes package node tests because Node detects reuse of the datadir through the NodeDatabase. * cmd/geth: make ethstats URL settable through config file * cmd/faucet: fix configuration * cmd/geth: dedup attach tests * eth: add comment for DefaultConfig * eth: pass downloader.SyncMode in Config This removes the FastSync, LightSync flags in favour of a more general SyncMode flag. * cmd/utils: remove jitvm flags * cmd/utils: make mutually exclusive flag error prettier It now reads: Fatal: flags --dev, --testnet can't be used at the same time * p2p: fix typo * node: add DefaultConfig, use it for geth * mobile: add missing NoDiscovery option * cmd/utils: drop MakeNode This exposed a couple of places that needed to be updated to use node.DefaultConfig. * node: fix typo * eth: make fast sync the default mode * cmd/utils: remove IPCApiFlag (unused) * node: remove default IPC path Set it in the frontends instead. * cmd/geth: add --syncmode * cmd/utils: make --ipcdisable and --ipcpath mutually exclusive * cmd/utils: don't enable WS, HTTP when setting addr * cmd/utils: fix --identity
This commit is contained in:
committed by
Péter Szilágyi
parent
b57680b0b2
commit
30d706c35e
19
vendor/github.com/naoina/go-stringutil/LICENSE
generated
vendored
Normal file
19
vendor/github.com/naoina/go-stringutil/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015 Naoya Inada <naoina@kuune.org>
|
||||
|
||||
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.
|
13
vendor/github.com/naoina/go-stringutil/README.md
generated
vendored
Normal file
13
vendor/github.com/naoina/go-stringutil/README.md
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# stringutil [](https://travis-ci.org/naoina/go-stringutil)
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/naoina/go-stringutil
|
||||
|
||||
## Documentation
|
||||
|
||||
See https://godoc.org/github.com/naoina/go-stringutil
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
253
vendor/github.com/naoina/go-stringutil/da.go
generated
vendored
Normal file
253
vendor/github.com/naoina/go-stringutil/da.go
generated
vendored
Normal file
@ -0,0 +1,253 @@
|
||||
package stringutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
terminationCharacter = '#'
|
||||
)
|
||||
|
||||
func mustDoubleArray(da *doubleArray, err error) *doubleArray {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return da
|
||||
}
|
||||
|
||||
func (da *doubleArray) Build(keys []string) error {
|
||||
records := makeRecords(keys)
|
||||
if err := da.build(records, 1, 0, make(map[int]struct{})); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type doubleArray struct {
|
||||
bc []baseCheck
|
||||
node []int
|
||||
}
|
||||
|
||||
func newDoubleArray(keys []string) (*doubleArray, error) {
|
||||
da := &doubleArray{
|
||||
bc: []baseCheck{0},
|
||||
node: []int{-1}, // A start index is adjusting to 1 because 0 will be used as a mark of non-existent node.
|
||||
}
|
||||
if err := da.Build(keys); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return da, nil
|
||||
}
|
||||
|
||||
// baseCheck contains BASE, CHECK and Extra flags.
|
||||
// From the top, 22bits of BASE, 2bits of Extra flags and 8bits of CHECK.
|
||||
//
|
||||
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
|
||||
// |----------------------|--|--------|
|
||||
// 32 10 8 0
|
||||
type baseCheck uint32
|
||||
|
||||
func (bc baseCheck) Base() int {
|
||||
return int(bc >> 10)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetBase(base int) {
|
||||
*bc |= baseCheck(base) << 10
|
||||
}
|
||||
|
||||
func (bc baseCheck) Check() byte {
|
||||
return byte(bc)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetCheck(check byte) {
|
||||
*bc |= baseCheck(check)
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsEmpty() bool {
|
||||
return bc&0xfffffcff == 0
|
||||
}
|
||||
|
||||
func (da *doubleArray) Lookup(path string) (length int) {
|
||||
idx := 1
|
||||
tmpIdx := idx
|
||||
for i := 0; i < len(path); i++ {
|
||||
c := path[i]
|
||||
tmpIdx = da.nextIndex(da.bc[tmpIdx].Base(), c)
|
||||
if tmpIdx >= len(da.bc) || da.bc[tmpIdx].Check() != c {
|
||||
break
|
||||
}
|
||||
idx = tmpIdx
|
||||
}
|
||||
if next := da.nextIndex(da.bc[idx].Base(), terminationCharacter); next < len(da.bc) && da.bc[next].Check() == terminationCharacter {
|
||||
return da.node[da.bc[next].Base()]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (da *doubleArray) LookupByBytes(path []byte) (length int) {
|
||||
idx := 1
|
||||
tmpIdx := idx
|
||||
for i := 0; i < len(path); i++ {
|
||||
c := path[i]
|
||||
tmpIdx = da.nextIndex(da.bc[tmpIdx].Base(), c)
|
||||
if tmpIdx >= len(da.bc) || da.bc[tmpIdx].Check() != c {
|
||||
break
|
||||
}
|
||||
idx = tmpIdx
|
||||
}
|
||||
if next := da.nextIndex(da.bc[idx].Base(), terminationCharacter); next < len(da.bc) && da.bc[next].Check() == terminationCharacter {
|
||||
return da.node[da.bc[next].Base()]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (da *doubleArray) build(srcs []record, idx, depth int, usedBase map[int]struct{}) error {
|
||||
sort.Stable(recordSlice(srcs))
|
||||
base, siblings, leaf, err := da.arrange(srcs, idx, depth, usedBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if leaf != nil {
|
||||
da.bc[idx].SetBase(len(da.node))
|
||||
da.node = append(da.node, leaf.value)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
da.setCheck(da.nextIndex(base, sib.c), sib.c)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
if err := da.build(srcs[sib.start:sib.end], da.nextIndex(base, sib.c), depth+1, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (da *doubleArray) setBase(i, base int) {
|
||||
da.bc[i].SetBase(base)
|
||||
}
|
||||
|
||||
func (da *doubleArray) setCheck(i int, check byte) {
|
||||
da.bc[i].SetCheck(check)
|
||||
}
|
||||
|
||||
func (da *doubleArray) findEmptyIndex(start int) int {
|
||||
i := start
|
||||
for ; i < len(da.bc); i++ {
|
||||
if da.bc[i].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// findBase returns good BASE.
|
||||
func (da *doubleArray) findBase(siblings []sibling, start int, usedBase map[int]struct{}) (base int) {
|
||||
for idx, firstChar := start+1, siblings[0].c; ; idx = da.findEmptyIndex(idx + 1) {
|
||||
base = da.nextIndex(idx, firstChar)
|
||||
if _, used := usedBase[base]; used {
|
||||
continue
|
||||
}
|
||||
i := 0
|
||||
for ; i < len(siblings); i++ {
|
||||
next := da.nextIndex(base, siblings[i].c)
|
||||
if len(da.bc) <= next {
|
||||
da.bc = append(da.bc, make([]baseCheck, next-len(da.bc)+1)...)
|
||||
}
|
||||
if !da.bc[next].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(siblings) {
|
||||
break
|
||||
}
|
||||
}
|
||||
usedBase[base] = struct{}{}
|
||||
return base
|
||||
}
|
||||
|
||||
func (da *doubleArray) arrange(records []record, idx, depth int, usedBase map[int]struct{}) (base int, siblings []sibling, leaf *record, err error) {
|
||||
siblings, leaf, err = makeSiblings(records, depth)
|
||||
if err != nil {
|
||||
return -1, nil, nil, err
|
||||
}
|
||||
if len(siblings) < 1 {
|
||||
return -1, nil, leaf, nil
|
||||
}
|
||||
base = da.findBase(siblings, idx, usedBase)
|
||||
da.setBase(idx, base)
|
||||
return base, siblings, leaf, err
|
||||
}
|
||||
|
||||
type sibling struct {
|
||||
start int
|
||||
end int
|
||||
c byte
|
||||
}
|
||||
|
||||
func (da *doubleArray) nextIndex(base int, c byte) int {
|
||||
return base ^ int(c)
|
||||
}
|
||||
|
||||
func makeSiblings(records []record, depth int) (sib []sibling, leaf *record, err error) {
|
||||
var (
|
||||
pc byte
|
||||
n int
|
||||
)
|
||||
for i, r := range records {
|
||||
if len(r.key) <= depth {
|
||||
leaf = &r
|
||||
continue
|
||||
}
|
||||
c := r.key[depth]
|
||||
switch {
|
||||
case pc < c:
|
||||
sib = append(sib, sibling{start: i, c: c})
|
||||
case pc == c:
|
||||
continue
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("stringutil: BUG: records hasn't been sorted")
|
||||
}
|
||||
if n > 0 {
|
||||
sib[n-1].end = i
|
||||
}
|
||||
pc = c
|
||||
n++
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, leaf, nil
|
||||
}
|
||||
sib[n-1].end = len(records)
|
||||
return sib, leaf, nil
|
||||
}
|
||||
|
||||
type record struct {
|
||||
key string
|
||||
value int
|
||||
}
|
||||
|
||||
func makeRecords(srcs []string) (records []record) {
|
||||
termChar := string(terminationCharacter)
|
||||
for _, s := range srcs {
|
||||
records = append(records, record{
|
||||
key: string(s + termChar),
|
||||
value: utf8.RuneCountInString(s),
|
||||
})
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
type recordSlice []record
|
||||
|
||||
func (rs recordSlice) Len() int {
|
||||
return len(rs)
|
||||
}
|
||||
|
||||
func (rs recordSlice) Less(i, j int) bool {
|
||||
return rs[i].key < rs[j].key
|
||||
}
|
||||
|
||||
func (rs recordSlice) Swap(i, j int) {
|
||||
rs[i], rs[j] = rs[j], rs[i]
|
||||
}
|
320
vendor/github.com/naoina/go-stringutil/strings.go
generated
vendored
Normal file
320
vendor/github.com/naoina/go-stringutil/strings.go
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
package stringutil
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
|
||||
// Based on https://github.com/golang/lint/blob/32a87160691b3c96046c0c678fe57c5bef761456/lint.go#L702
|
||||
commonInitialismMap = map[string]struct{}{
|
||||
"API": struct{}{},
|
||||
"ASCII": struct{}{},
|
||||
"CPU": struct{}{},
|
||||
"CSRF": struct{}{},
|
||||
"CSS": struct{}{},
|
||||
"DNS": struct{}{},
|
||||
"EOF": struct{}{},
|
||||
"GUID": struct{}{},
|
||||
"HTML": struct{}{},
|
||||
"HTTP": struct{}{},
|
||||
"HTTPS": struct{}{},
|
||||
"ID": struct{}{},
|
||||
"IP": struct{}{},
|
||||
"JSON": struct{}{},
|
||||
"LHS": struct{}{},
|
||||
"QPS": struct{}{},
|
||||
"RAM": struct{}{},
|
||||
"RHS": struct{}{},
|
||||
"RPC": struct{}{},
|
||||
"SLA": struct{}{},
|
||||
"SMTP": struct{}{},
|
||||
"SQL": struct{}{},
|
||||
"SSH": struct{}{},
|
||||
"TCP": struct{}{},
|
||||
"TLS": struct{}{},
|
||||
"TTL": struct{}{},
|
||||
"UDP": struct{}{},
|
||||
"UI": struct{}{},
|
||||
"UID": struct{}{},
|
||||
"UUID": struct{}{},
|
||||
"URI": struct{}{},
|
||||
"URL": struct{}{},
|
||||
"UTF8": struct{}{},
|
||||
"VM": struct{}{},
|
||||
"XML": struct{}{},
|
||||
"XSRF": struct{}{},
|
||||
"XSS": struct{}{},
|
||||
}
|
||||
commonInitialisms = keys(commonInitialismMap)
|
||||
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
|
||||
longestLen = longestLength(commonInitialisms)
|
||||
shortestLen = shortestLength(commonInitialisms, longestLen)
|
||||
)
|
||||
|
||||
// ToUpperCamelCase returns a copy of the string s with all Unicode letters mapped to their camel case.
|
||||
// It will convert to upper case previous letter of '_' and first letter, and remove letter of '_'.
|
||||
func ToUpperCamelCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
upper := true
|
||||
start := 0
|
||||
result := make([]byte, 0, len(s))
|
||||
var runeBuf [utf8.UTFMax]byte
|
||||
var initialism []byte
|
||||
for _, c := range s {
|
||||
if c == '_' {
|
||||
upper = true
|
||||
candidate := string(result[start:])
|
||||
initialism = initialism[:0]
|
||||
for _, r := range candidate {
|
||||
if r < utf8.RuneSelf {
|
||||
initialism = append(initialism, toUpperASCII(byte(r)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(r))
|
||||
initialism = append(initialism, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
start = len(result)
|
||||
continue
|
||||
}
|
||||
if upper {
|
||||
if c < utf8.RuneSelf {
|
||||
result = append(result, toUpperASCII(byte(c)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(c))
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
upper = false
|
||||
continue
|
||||
}
|
||||
if c < utf8.RuneSelf {
|
||||
result = append(result, byte(c))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], c)
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
candidate := string(result[start:])
|
||||
initialism = initialism[:0]
|
||||
for _, r := range candidate {
|
||||
if r < utf8.RuneSelf {
|
||||
initialism = append(initialism, toUpperASCII(byte(r)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(r))
|
||||
initialism = append(initialism, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToUpperCamelCaseASCII is similar to ToUpperCamelCase, but optimized for
|
||||
// only the ASCII characters.
|
||||
// ToUpperCamelCaseASCII is faster than ToUpperCamelCase, but doesn't work if
|
||||
// contains non-ASCII characters.
|
||||
func ToUpperCamelCaseASCII(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
upper := true
|
||||
start := 0
|
||||
result := make([]byte, 0, len(s))
|
||||
var initialism []byte
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '_' {
|
||||
upper = true
|
||||
candidate := result[start:]
|
||||
initialism = initialism[:0]
|
||||
for _, b := range candidate {
|
||||
initialism = append(initialism, toUpperASCII(b))
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
start = len(result)
|
||||
continue
|
||||
}
|
||||
if upper {
|
||||
result = append(result, toUpperASCII(c))
|
||||
upper = false
|
||||
continue
|
||||
}
|
||||
result = append(result, c)
|
||||
}
|
||||
candidate := result[start:]
|
||||
initialism = initialism[:0]
|
||||
for _, b := range candidate {
|
||||
initialism = append(initialism, toUpperASCII(b))
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToSnakeCase returns a copy of the string s with all Unicode letters mapped to their snake case.
|
||||
// It will insert letter of '_' at position of previous letter of uppercase and all
|
||||
// letters convert to lower case.
|
||||
// ToSnakeCase does not insert '_' letter into a common initialism word like ID, URL and so on.
|
||||
func ToSnakeCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
result := make([]byte, 0, len(s))
|
||||
var runeBuf [utf8.UTFMax]byte
|
||||
var j, skipCount int
|
||||
for i, c := range s {
|
||||
if i < skipCount {
|
||||
continue
|
||||
}
|
||||
if unicode.IsUpper(c) {
|
||||
if i != 0 {
|
||||
result = append(result, '_')
|
||||
}
|
||||
next := nextIndex(j, len(s))
|
||||
if length := commonInitialism.Lookup(s[j:next]); length > 0 {
|
||||
for _, r := range s[j : j+length] {
|
||||
if r < utf8.RuneSelf {
|
||||
result = append(result, toLowerASCII(byte(r)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToLower(r))
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
j += length - 1
|
||||
skipCount = i + length
|
||||
continue
|
||||
}
|
||||
}
|
||||
if c < utf8.RuneSelf {
|
||||
result = append(result, toLowerASCII(byte(c)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToLower(c))
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
j++
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToSnakeCaseASCII is similar to ToSnakeCase, but optimized for only the ASCII
|
||||
// characters.
|
||||
// ToSnakeCaseASCII is faster than ToSnakeCase, but doesn't work correctly if
|
||||
// contains non-ASCII characters.
|
||||
func ToSnakeCaseASCII(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
result := make([]byte, 0, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if isUpperASCII(c) {
|
||||
if i != 0 {
|
||||
result = append(result, '_')
|
||||
}
|
||||
if k := i + shortestLen - 1; k < len(s) && isUpperASCII(s[k]) {
|
||||
if length := commonInitialism.Lookup(s[i:nextIndex(i, len(s))]); length > 0 {
|
||||
for j, buf := 0, s[i:i+length]; j < len(buf); j++ {
|
||||
result = append(result, toLowerASCII(buf[j]))
|
||||
}
|
||||
i += length - 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
result = append(result, toLowerASCII(c))
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// AddCommonInitialism adds ss to list of common initialisms.
|
||||
func AddCommonInitialism(ss ...string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, s := range ss {
|
||||
commonInitialismMap[s] = struct{}{}
|
||||
}
|
||||
commonInitialisms = keys(commonInitialismMap)
|
||||
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
|
||||
longestLen = longestLength(commonInitialisms)
|
||||
shortestLen = shortestLength(commonInitialisms, longestLen)
|
||||
}
|
||||
|
||||
// DelCommonInitialism deletes ss from list of common initialisms.
|
||||
func DelCommonInitialism(ss ...string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, s := range ss {
|
||||
delete(commonInitialismMap, s)
|
||||
}
|
||||
commonInitialisms = keys(commonInitialismMap)
|
||||
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
|
||||
longestLen = longestLength(commonInitialisms)
|
||||
shortestLen = shortestLength(commonInitialisms, longestLen)
|
||||
}
|
||||
|
||||
func isUpperASCII(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z'
|
||||
}
|
||||
|
||||
func isLowerASCII(c byte) bool {
|
||||
return 'a' <= c && c <= 'z'
|
||||
}
|
||||
|
||||
func toUpperASCII(c byte) byte {
|
||||
if isLowerASCII(c) {
|
||||
return c - ('a' - 'A')
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func toLowerASCII(c byte) byte {
|
||||
if isUpperASCII(c) {
|
||||
return c + 'a' - 'A'
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func nextIndex(i, maxlen int) int {
|
||||
if n := i + longestLen; n < maxlen {
|
||||
return n
|
||||
}
|
||||
return maxlen
|
||||
}
|
||||
|
||||
func keys(m map[string]struct{}) []string {
|
||||
result := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
result = append(result, k)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func shortestLength(strs []string, shortest int) int {
|
||||
for _, s := range strs {
|
||||
if candidate := utf8.RuneCountInString(s); candidate < shortest {
|
||||
shortest = candidate
|
||||
}
|
||||
}
|
||||
return shortest
|
||||
}
|
||||
|
||||
func longestLength(strs []string) (longest int) {
|
||||
for _, s := range strs {
|
||||
if candidate := utf8.RuneCountInString(s); candidate > longest {
|
||||
longest = candidate
|
||||
}
|
||||
}
|
||||
return longest
|
||||
}
|
19
vendor/github.com/naoina/toml/LICENSE
generated
vendored
Normal file
19
vendor/github.com/naoina/toml/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
|
||||
|
||||
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.
|
392
vendor/github.com/naoina/toml/README.md
generated
vendored
Normal file
392
vendor/github.com/naoina/toml/README.md
generated
vendored
Normal file
@ -0,0 +1,392 @@
|
||||
# TOML parser and encoder library for Golang [](https://travis-ci.org/naoina/toml)
|
||||
|
||||
[TOML](https://github.com/toml-lang/toml) parser and encoder library for [Golang](http://golang.org/).
|
||||
|
||||
This library is compatible with TOML version [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md).
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/naoina/toml
|
||||
|
||||
## Usage
|
||||
|
||||
The following TOML save as `example.toml`.
|
||||
|
||||
```toml
|
||||
# This is a TOML document. Boom.
|
||||
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Lance Uppercut"
|
||||
dob = 1979-05-27T07:32:00-08:00 # First class dates? Why not?
|
||||
|
||||
[database]
|
||||
server = "192.168.1.1"
|
||||
ports = [ 8001, 8001, 8002 ]
|
||||
connection_max = 5000
|
||||
enabled = true
|
||||
|
||||
[servers]
|
||||
|
||||
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
dc = "eqdc10"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
dc = "eqdc10"
|
||||
|
||||
[clients]
|
||||
data = [ ["gamma", "delta"], [1, 2] ]
|
||||
|
||||
# Line breaks are OK when inside arrays
|
||||
hosts = [
|
||||
"alpha",
|
||||
"omega"
|
||||
]
|
||||
```
|
||||
|
||||
Then above TOML will mapping to `tomlConfig` struct using `toml.Unmarshal`.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
type tomlConfig struct {
|
||||
Title string
|
||||
Owner struct {
|
||||
Name string
|
||||
Dob time.Time
|
||||
}
|
||||
Database struct {
|
||||
Server string
|
||||
Ports []int
|
||||
ConnectionMax uint
|
||||
Enabled bool
|
||||
}
|
||||
Servers map[string]ServerInfo
|
||||
Clients struct {
|
||||
Data [][]interface{}
|
||||
Hosts []string
|
||||
}
|
||||
}
|
||||
|
||||
type ServerInfo struct {
|
||||
IP net.IP
|
||||
DC string
|
||||
}
|
||||
|
||||
func main() {
|
||||
f, err := os.Open("example.toml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
var config Config
|
||||
if err := toml.NewDecoder(f).Decode(&config); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// then to use the unmarshaled config...
|
||||
fmt.Println("IP of server 'alpha':", config.Servers["alpha"].IP)
|
||||
}
|
||||
```
|
||||
|
||||
## Mappings
|
||||
|
||||
A key and value of TOML will map to the corresponding field.
|
||||
The fields of struct for mapping must be exported.
|
||||
|
||||
The rules of the mapping of key are following:
|
||||
|
||||
#### Exact matching
|
||||
|
||||
```toml
|
||||
timeout_seconds = 256
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Timeout_seconds int
|
||||
}
|
||||
```
|
||||
|
||||
#### Camelcase matching
|
||||
|
||||
```toml
|
||||
server_name = "srv1"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
ServerName string
|
||||
}
|
||||
```
|
||||
|
||||
#### Uppercase matching
|
||||
|
||||
```toml
|
||||
ip = "10.0.0.1"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
IP string
|
||||
}
|
||||
```
|
||||
|
||||
See the following examples for the value mappings.
|
||||
|
||||
### String
|
||||
|
||||
```toml
|
||||
val = "string"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val string
|
||||
}
|
||||
```
|
||||
|
||||
### Integer
|
||||
|
||||
```toml
|
||||
val = 100
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val int
|
||||
}
|
||||
```
|
||||
|
||||
All types that can be used are following:
|
||||
|
||||
* int8 (from `-128` to `127`)
|
||||
* int16 (from `-32768` to `32767`)
|
||||
* int32 (from `-2147483648` to `2147483647`)
|
||||
* int64 (from `-9223372036854775808` to `9223372036854775807`)
|
||||
* int (same as `int32` on 32bit environment, or `int64` on 64bit environment)
|
||||
* uint8 (from `0` to `255`)
|
||||
* uint16 (from `0` to `65535`)
|
||||
* uint32 (from `0` to `4294967295`)
|
||||
* uint64 (from `0` to `18446744073709551615`)
|
||||
* uint (same as `uint` on 32bit environment, or `uint64` on 64bit environment)
|
||||
|
||||
### Float
|
||||
|
||||
```toml
|
||||
val = 3.1415
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val float32
|
||||
}
|
||||
```
|
||||
|
||||
All types that can be used are following:
|
||||
|
||||
* float32
|
||||
* float64
|
||||
|
||||
### Boolean
|
||||
|
||||
```toml
|
||||
val = true
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val bool
|
||||
}
|
||||
```
|
||||
|
||||
### Datetime
|
||||
|
||||
```toml
|
||||
val = 2014-09-28T21:27:39Z
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val time.Time
|
||||
}
|
||||
```
|
||||
|
||||
### Array
|
||||
|
||||
```toml
|
||||
val = ["a", "b", "c"]
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val []string
|
||||
}
|
||||
```
|
||||
|
||||
Also following examples all can be mapped:
|
||||
|
||||
```toml
|
||||
val1 = [1, 2, 3]
|
||||
val2 = [["a", "b"], ["c", "d"]]
|
||||
val3 = [[1, 2, 3], ["a", "b", "c"]]
|
||||
val4 = [[1, 2, 3], [["a", "b"], [true, false]]]
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val1 []int
|
||||
Val2 [][]string
|
||||
Val3 [][]interface{}
|
||||
Val4 [][]interface{}
|
||||
}
|
||||
```
|
||||
|
||||
### Table
|
||||
|
||||
```toml
|
||||
[server]
|
||||
type = "app"
|
||||
|
||||
[server.development]
|
||||
ip = "10.0.0.1"
|
||||
|
||||
[server.production]
|
||||
ip = "10.0.0.2"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Server map[string]Server
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IP string
|
||||
}
|
||||
```
|
||||
|
||||
You can also use the following struct instead of map of struct.
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Server struct {
|
||||
Development Server
|
||||
Production Server
|
||||
}
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IP string
|
||||
}
|
||||
```
|
||||
|
||||
### Array of Tables
|
||||
|
||||
```toml
|
||||
[[fruit]]
|
||||
name = "apple"
|
||||
|
||||
[fruit.physical]
|
||||
color = "red"
|
||||
shape = "round"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "red delicious"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "granny smith"
|
||||
|
||||
[[fruit]]
|
||||
name = "banana"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "plantain"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Fruit []struct {
|
||||
Name string
|
||||
Physical struct {
|
||||
Color string
|
||||
Shape string
|
||||
}
|
||||
Variety []struct {
|
||||
Name string
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using the `encoding.TextUnmarshaler` interface
|
||||
|
||||
Package toml supports `encoding.TextUnmarshaler` (and `encoding.TextMarshaler`). You can
|
||||
use it to apply custom marshaling rules for certain types. The `UnmarshalText` method is
|
||||
called with the value text found in the TOML input. TOML strings are passed unquoted.
|
||||
|
||||
```toml
|
||||
duration = "10s"
|
||||
```
|
||||
|
||||
```go
|
||||
import time
|
||||
|
||||
type Duration time.Duration
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler
|
||||
func (d *Duration) UnmarshalText(data []byte) error {
|
||||
duration, err := time.ParseDuration(string(data))
|
||||
if err == nil {
|
||||
*d = Duration(duration)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler
|
||||
func (d Duration) MarshalText() ([]byte, error) {
|
||||
return []byte(time.Duration(d).String()), nil
|
||||
}
|
||||
|
||||
type ConfigWithDuration struct {
|
||||
Duration Duration
|
||||
}
|
||||
```
|
||||
### Using the `toml.UnmarshalerRec` interface
|
||||
|
||||
You can also override marshaling rules specifically for TOML using the `UnmarshalerRec`
|
||||
and `MarshalerRec` interfaces. These are useful if you want to control how structs or
|
||||
arrays are handled. You can apply additional validation or set unexported struct fields.
|
||||
|
||||
Note: `encoding.TextUnmarshaler` and `encoding.TextMarshaler` should be preferred for
|
||||
simple (scalar) values because they're also compatible with other formats like JSON or
|
||||
YAML.
|
||||
|
||||
[See the UnmarshalerRec example](https://godoc.org/github.com/naoina/toml/#example_UnmarshalerRec).
|
||||
|
||||
### Using the `toml.Unmarshaler` interface
|
||||
|
||||
If you want to deal with raw TOML syntax, use the `Unmarshaler` and `Marshaler`
|
||||
interfaces. Their input and output is raw TOML syntax. As such, these interfaces are
|
||||
useful if you want to handle TOML at the syntax level.
|
||||
|
||||
[See the Unmarshaler example](https://godoc.org/github.com/naoina/toml/#example_Unmarshaler).
|
||||
|
||||
## API documentation
|
||||
|
||||
See [Godoc](http://godoc.org/github.com/naoina/toml).
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
192
vendor/github.com/naoina/toml/ast/ast.go
generated
vendored
Normal file
192
vendor/github.com/naoina/toml/ast/ast.go
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Position struct {
|
||||
Begin int
|
||||
End int
|
||||
}
|
||||
|
||||
type Value interface {
|
||||
Pos() int
|
||||
End() int
|
||||
Source() string
|
||||
}
|
||||
|
||||
type String struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (s *String) Pos() int {
|
||||
return s.Position.Begin
|
||||
}
|
||||
|
||||
func (s *String) End() int {
|
||||
return s.Position.End
|
||||
}
|
||||
|
||||
func (s *String) Source() string {
|
||||
return string(s.Data)
|
||||
}
|
||||
|
||||
type Integer struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (i *Integer) Pos() int {
|
||||
return i.Position.Begin
|
||||
}
|
||||
|
||||
func (i *Integer) End() int {
|
||||
return i.Position.End
|
||||
}
|
||||
|
||||
func (i *Integer) Source() string {
|
||||
return string(i.Data)
|
||||
}
|
||||
|
||||
func (i *Integer) Int() (int64, error) {
|
||||
return strconv.ParseInt(i.Value, 10, 64)
|
||||
}
|
||||
|
||||
type Float struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (f *Float) Pos() int {
|
||||
return f.Position.Begin
|
||||
}
|
||||
|
||||
func (f *Float) End() int {
|
||||
return f.Position.End
|
||||
}
|
||||
|
||||
func (f *Float) Source() string {
|
||||
return string(f.Data)
|
||||
}
|
||||
|
||||
func (f *Float) Float() (float64, error) {
|
||||
return strconv.ParseFloat(f.Value, 64)
|
||||
}
|
||||
|
||||
type Boolean struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (b *Boolean) Pos() int {
|
||||
return b.Position.Begin
|
||||
}
|
||||
|
||||
func (b *Boolean) End() int {
|
||||
return b.Position.End
|
||||
}
|
||||
|
||||
func (b *Boolean) Source() string {
|
||||
return string(b.Data)
|
||||
}
|
||||
|
||||
func (b *Boolean) Boolean() (bool, error) {
|
||||
return strconv.ParseBool(b.Value)
|
||||
}
|
||||
|
||||
type Datetime struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (d *Datetime) Pos() int {
|
||||
return d.Position.Begin
|
||||
}
|
||||
|
||||
func (d *Datetime) End() int {
|
||||
return d.Position.End
|
||||
}
|
||||
|
||||
func (d *Datetime) Source() string {
|
||||
return string(d.Data)
|
||||
}
|
||||
|
||||
func (d *Datetime) Time() (time.Time, error) {
|
||||
switch {
|
||||
case !strings.Contains(d.Value, ":"):
|
||||
return time.Parse("2006-01-02", d.Value)
|
||||
case !strings.Contains(d.Value, "-"):
|
||||
return time.Parse("15:04:05.999999999", d.Value)
|
||||
default:
|
||||
return time.Parse(time.RFC3339Nano, d.Value)
|
||||
}
|
||||
}
|
||||
|
||||
type Array struct {
|
||||
Position Position
|
||||
Value []Value
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (a *Array) Pos() int {
|
||||
return a.Position.Begin
|
||||
}
|
||||
|
||||
func (a *Array) End() int {
|
||||
return a.Position.End
|
||||
}
|
||||
|
||||
func (a *Array) Source() string {
|
||||
return string(a.Data)
|
||||
}
|
||||
|
||||
type TableType uint8
|
||||
|
||||
const (
|
||||
TableTypeNormal TableType = iota
|
||||
TableTypeArray
|
||||
)
|
||||
|
||||
var tableTypes = [...]string{
|
||||
"normal",
|
||||
"array",
|
||||
}
|
||||
|
||||
func (t TableType) String() string {
|
||||
return tableTypes[t]
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
Position Position
|
||||
Line int
|
||||
Name string
|
||||
Fields map[string]interface{}
|
||||
Type TableType
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (t *Table) Pos() int {
|
||||
return t.Position.Begin
|
||||
}
|
||||
|
||||
func (t *Table) End() int {
|
||||
return t.Position.End
|
||||
}
|
||||
|
||||
func (t *Table) Source() string {
|
||||
return string(t.Data)
|
||||
}
|
||||
|
||||
type KeyValue struct {
|
||||
Key string
|
||||
Value Value
|
||||
Line int
|
||||
}
|
86
vendor/github.com/naoina/toml/config.go
generated
vendored
Normal file
86
vendor/github.com/naoina/toml/config.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
stringutil "github.com/naoina/go-stringutil"
|
||||
"github.com/naoina/toml/ast"
|
||||
)
|
||||
|
||||
// Config contains options for encoding and decoding.
|
||||
type Config struct {
|
||||
// NormFieldName is used to match TOML keys to struct fields. The function runs for
|
||||
// both input keys and struct field names and should return a string that makes the
|
||||
// two match. You must set this field to use the decoder.
|
||||
//
|
||||
// Example: The function in the default config removes _ and lowercases all keys. This
|
||||
// allows a key called 'api_key' to match the struct field 'APIKey' because both are
|
||||
// normalized to 'apikey'.
|
||||
//
|
||||
// Note that NormFieldName is not used for fields which define a TOML
|
||||
// key through the struct tag.
|
||||
NormFieldName func(typ reflect.Type, keyOrField string) string
|
||||
|
||||
// FieldToKey determines the TOML key of a struct field when encoding.
|
||||
// You must set this field to use the encoder.
|
||||
//
|
||||
// Note that FieldToKey is not used for fields which define a TOML
|
||||
// key through the struct tag.
|
||||
FieldToKey func(typ reflect.Type, field string) string
|
||||
|
||||
// MissingField, if non-nil, is called when the decoder encounters a key for which no
|
||||
// matching struct field exists. The default behavior is to return an error.
|
||||
MissingField func(typ reflect.Type, key string) error
|
||||
}
|
||||
|
||||
// DefaultConfig contains the default options for encoding and decoding.
|
||||
// Snake case (i.e. 'foo_bar') is used for key names.
|
||||
var DefaultConfig = Config{
|
||||
NormFieldName: defaultNormFieldName,
|
||||
FieldToKey: snakeCase,
|
||||
}
|
||||
|
||||
func defaultNormFieldName(typ reflect.Type, s string) string {
|
||||
return strings.Replace(strings.ToLower(s), "_", "", -1)
|
||||
}
|
||||
|
||||
func snakeCase(typ reflect.Type, s string) string {
|
||||
return stringutil.ToSnakeCase(s)
|
||||
}
|
||||
|
||||
func defaultMissingField(typ reflect.Type, key string) error {
|
||||
return fmt.Errorf("field corresponding to `%s' is not defined in %v", key, typ)
|
||||
}
|
||||
|
||||
// NewEncoder returns a new Encoder that writes to w.
|
||||
// It is shorthand for DefaultConfig.NewEncoder(w).
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return DefaultConfig.NewEncoder(w)
|
||||
}
|
||||
|
||||
// Marshal returns the TOML encoding of v.
|
||||
// It is shorthand for DefaultConfig.Marshal(v).
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
return DefaultConfig.Marshal(v)
|
||||
}
|
||||
|
||||
// Unmarshal parses the TOML data and stores the result in the value pointed to by v.
|
||||
// It is shorthand for DefaultConfig.Unmarshal(data, v).
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
return DefaultConfig.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// UnmarshalTable applies the contents of an ast.Table to the value pointed at by v.
|
||||
// It is shorthand for DefaultConfig.UnmarshalTable(t, v).
|
||||
func UnmarshalTable(t *ast.Table, v interface{}) error {
|
||||
return DefaultConfig.UnmarshalTable(t, v)
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder that reads from r.
|
||||
// It is shorthand for DefaultConfig.NewDecoder(r).
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
return DefaultConfig.NewDecoder(r)
|
||||
}
|
478
vendor/github.com/naoina/toml/decode.go
generated
vendored
Normal file
478
vendor/github.com/naoina/toml/decode.go
generated
vendored
Normal file
@ -0,0 +1,478 @@
|
||||
// Package toml encodes and decodes the TOML configuration format using reflection.
|
||||
//
|
||||
// This library is compatible with TOML version v0.4.0.
|
||||
package toml
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/naoina/toml/ast"
|
||||
)
|
||||
|
||||
const (
|
||||
tableSeparator = '.'
|
||||
)
|
||||
|
||||
var (
|
||||
escapeReplacer = strings.NewReplacer(
|
||||
"\b", "\\n",
|
||||
"\f", "\\f",
|
||||
"\n", "\\n",
|
||||
"\r", "\\r",
|
||||
"\t", "\\t",
|
||||
)
|
||||
underscoreReplacer = strings.NewReplacer(
|
||||
"_", "",
|
||||
)
|
||||
)
|
||||
|
||||
var timeType = reflect.TypeOf(time.Time{})
|
||||
|
||||
// Unmarshal parses the TOML data and stores the result in the value pointed to by v.
|
||||
//
|
||||
// Unmarshal will mapped to v that according to following rules:
|
||||
//
|
||||
// TOML strings to string
|
||||
// TOML integers to any int type
|
||||
// TOML floats to float32 or float64
|
||||
// TOML booleans to bool
|
||||
// TOML datetimes to time.Time
|
||||
// TOML arrays to any type of slice
|
||||
// TOML tables to struct or map
|
||||
// TOML array tables to slice of struct or map
|
||||
func (cfg *Config) Unmarshal(data []byte, v interface{}) error {
|
||||
table, err := Parse(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.UnmarshalTable(table, v); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A Decoder reads and decodes TOML from an input stream.
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder that reads from r.
|
||||
// Note that it reads all from r before parsing it.
|
||||
func (cfg *Config) NewDecoder(r io.Reader) *Decoder {
|
||||
return &Decoder{r, cfg}
|
||||
}
|
||||
|
||||
// Decode parses the TOML data from its input and stores it in the value pointed to by v.
|
||||
// See the documentation for Unmarshal for details about the conversion of TOML into a Go value.
|
||||
func (d *Decoder) Decode(v interface{}) error {
|
||||
b, err := ioutil.ReadAll(d.r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.cfg.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
// UnmarshalerRec may be implemented by types to customize their behavior when being
|
||||
// unmarshaled from TOML. You can use it to implement custom validation or to set
|
||||
// unexported fields.
|
||||
//
|
||||
// UnmarshalTOML receives a function that can be called to unmarshal the original TOML
|
||||
// value into a field or variable. It is safe to call the function more than once if
|
||||
// necessary.
|
||||
type UnmarshalerRec interface {
|
||||
UnmarshalTOML(fn func(interface{}) error) error
|
||||
}
|
||||
|
||||
// Unmarshaler can be used to capture and process raw TOML source of a table or value.
|
||||
// UnmarshalTOML must copy the input if it wishes to retain it after returning.
|
||||
//
|
||||
// Note: this interface is retained for backwards compatibility. You probably want
|
||||
// to implement encoding.TextUnmarshaler or UnmarshalerRec instead.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTOML(input []byte) error
|
||||
}
|
||||
|
||||
// UnmarshalTable applies the contents of an ast.Table to the value pointed at by v.
|
||||
//
|
||||
// UnmarshalTable will mapped to v that according to following rules:
|
||||
//
|
||||
// TOML strings to string
|
||||
// TOML integers to any int type
|
||||
// TOML floats to float32 or float64
|
||||
// TOML booleans to bool
|
||||
// TOML datetimes to time.Time
|
||||
// TOML arrays to any type of slice
|
||||
// TOML tables to struct or map
|
||||
// TOML array tables to slice of struct or map
|
||||
func (cfg *Config) UnmarshalTable(t *ast.Table, v interface{}) error {
|
||||
rv := reflect.ValueOf(v)
|
||||
toplevelMap := rv.Kind() == reflect.Map
|
||||
if (!toplevelMap && rv.Kind() != reflect.Ptr) || rv.IsNil() {
|
||||
return &invalidUnmarshalError{reflect.TypeOf(v)}
|
||||
}
|
||||
return unmarshalTable(cfg, rv, t, toplevelMap)
|
||||
}
|
||||
|
||||
// used for UnmarshalerRec.
|
||||
func unmarshalTableOrValue(cfg *Config, rv reflect.Value, av interface{}) error {
|
||||
if (rv.Kind() != reflect.Ptr && rv.Kind() != reflect.Map) || rv.IsNil() {
|
||||
return &invalidUnmarshalError{rv.Type()}
|
||||
}
|
||||
rv = indirect(rv)
|
||||
|
||||
switch av.(type) {
|
||||
case *ast.KeyValue, *ast.Table, []*ast.Table:
|
||||
if err := unmarshalField(cfg, rv, av); err != nil {
|
||||
return lineError(fieldLineNumber(av), err)
|
||||
}
|
||||
return nil
|
||||
case ast.Value:
|
||||
return setValue(cfg, rv, av.(ast.Value))
|
||||
default:
|
||||
panic(fmt.Sprintf("BUG: unhandled AST node type %T", av))
|
||||
}
|
||||
}
|
||||
|
||||
// unmarshalTable unmarshals the fields of a table into a struct or map.
|
||||
//
|
||||
// toplevelMap is true when rv is an (unadressable) map given to UnmarshalTable. In this
|
||||
// (special) case, the map is used as-is instead of creating a new map.
|
||||
func unmarshalTable(cfg *Config, rv reflect.Value, t *ast.Table, toplevelMap bool) error {
|
||||
rv = indirect(rv)
|
||||
if err, ok := setUnmarshaler(cfg, rv, t); ok {
|
||||
return lineError(t.Line, err)
|
||||
}
|
||||
switch {
|
||||
case rv.Kind() == reflect.Struct:
|
||||
fc := makeFieldCache(cfg, rv.Type())
|
||||
for key, fieldAst := range t.Fields {
|
||||
fv, fieldName, err := fc.findField(cfg, rv, key)
|
||||
if err != nil {
|
||||
return lineError(fieldLineNumber(fieldAst), err)
|
||||
}
|
||||
if fv.IsValid() {
|
||||
if err := unmarshalField(cfg, fv, fieldAst); err != nil {
|
||||
return lineErrorField(fieldLineNumber(fieldAst), rv.Type().String()+"."+fieldName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case rv.Kind() == reflect.Map || isEface(rv):
|
||||
m := rv
|
||||
if !toplevelMap {
|
||||
if rv.Kind() == reflect.Interface {
|
||||
m = reflect.ValueOf(make(map[string]interface{}))
|
||||
} else {
|
||||
m = reflect.MakeMap(rv.Type())
|
||||
}
|
||||
}
|
||||
elemtyp := m.Type().Elem()
|
||||
for key, fieldAst := range t.Fields {
|
||||
kv, err := unmarshalMapKey(m.Type().Key(), key)
|
||||
if err != nil {
|
||||
return lineError(fieldLineNumber(fieldAst), err)
|
||||
}
|
||||
fv := reflect.New(elemtyp).Elem()
|
||||
if err := unmarshalField(cfg, fv, fieldAst); err != nil {
|
||||
return lineError(fieldLineNumber(fieldAst), err)
|
||||
}
|
||||
m.SetMapIndex(kv, fv)
|
||||
}
|
||||
if !toplevelMap {
|
||||
rv.Set(m)
|
||||
}
|
||||
default:
|
||||
return lineError(t.Line, &unmarshalTypeError{"table", "struct or map", rv.Type()})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fieldLineNumber(fieldAst interface{}) int {
|
||||
switch av := fieldAst.(type) {
|
||||
case *ast.KeyValue:
|
||||
return av.Line
|
||||
case *ast.Table:
|
||||
return av.Line
|
||||
case []*ast.Table:
|
||||
return av[0].Line
|
||||
default:
|
||||
panic(fmt.Sprintf("BUG: unhandled node type %T", fieldAst))
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalField(cfg *Config, rv reflect.Value, fieldAst interface{}) error {
|
||||
switch av := fieldAst.(type) {
|
||||
case *ast.KeyValue:
|
||||
return setValue(cfg, rv, av.Value)
|
||||
case *ast.Table:
|
||||
return unmarshalTable(cfg, rv, av, false)
|
||||
case []*ast.Table:
|
||||
rv = indirect(rv)
|
||||
if err, ok := setUnmarshaler(cfg, rv, fieldAst); ok {
|
||||
return err
|
||||
}
|
||||
var slice reflect.Value
|
||||
switch {
|
||||
case rv.Kind() == reflect.Slice:
|
||||
slice = reflect.MakeSlice(rv.Type(), len(av), len(av))
|
||||
case isEface(rv):
|
||||
slice = reflect.ValueOf(make([]interface{}, len(av)))
|
||||
default:
|
||||
return &unmarshalTypeError{"array table", "slice", rv.Type()}
|
||||
}
|
||||
for i, tbl := range av {
|
||||
vv := reflect.New(slice.Type().Elem()).Elem()
|
||||
if err := unmarshalTable(cfg, vv, tbl, false); err != nil {
|
||||
return err
|
||||
}
|
||||
slice.Index(i).Set(vv)
|
||||
}
|
||||
rv.Set(slice)
|
||||
default:
|
||||
panic(fmt.Sprintf("BUG: unhandled AST node type %T", av))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalMapKey(typ reflect.Type, key string) (reflect.Value, error) {
|
||||
rv := reflect.New(typ).Elem()
|
||||
if u, ok := rv.Addr().Interface().(encoding.TextUnmarshaler); ok {
|
||||
return rv, u.UnmarshalText([]byte(key))
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.String:
|
||||
rv.SetString(key)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
i, err := strconv.ParseInt(key, 10, int(typ.Size()*8))
|
||||
if err != nil {
|
||||
return rv, convertNumError(typ.Kind(), err)
|
||||
}
|
||||
rv.SetInt(i)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
i, err := strconv.ParseUint(key, 10, int(typ.Size()*8))
|
||||
if err != nil {
|
||||
return rv, convertNumError(typ.Kind(), err)
|
||||
}
|
||||
rv.SetUint(i)
|
||||
default:
|
||||
return rv, fmt.Errorf("invalid map key type %s", typ)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func setValue(cfg *Config, lhs reflect.Value, val ast.Value) error {
|
||||
lhs = indirect(lhs)
|
||||
if err, ok := setUnmarshaler(cfg, lhs, val); ok {
|
||||
return err
|
||||
}
|
||||
if err, ok := setTextUnmarshaler(lhs, val); ok {
|
||||
return err
|
||||
}
|
||||
switch v := val.(type) {
|
||||
case *ast.Integer:
|
||||
return setInt(lhs, v)
|
||||
case *ast.Float:
|
||||
return setFloat(lhs, v)
|
||||
case *ast.String:
|
||||
return setString(lhs, v)
|
||||
case *ast.Boolean:
|
||||
return setBoolean(lhs, v)
|
||||
case *ast.Datetime:
|
||||
return setDatetime(lhs, v)
|
||||
case *ast.Array:
|
||||
return setArray(cfg, lhs, v)
|
||||
default:
|
||||
panic(fmt.Sprintf("BUG: unhandled node type %T", v))
|
||||
}
|
||||
}
|
||||
|
||||
func indirect(rv reflect.Value) reflect.Value {
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
rv.Set(reflect.New(rv.Type().Elem()))
|
||||
}
|
||||
rv = rv.Elem()
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func setUnmarshaler(cfg *Config, lhs reflect.Value, av interface{}) (error, bool) {
|
||||
if lhs.CanAddr() {
|
||||
if u, ok := lhs.Addr().Interface().(UnmarshalerRec); ok {
|
||||
err := u.UnmarshalTOML(func(v interface{}) error {
|
||||
return unmarshalTableOrValue(cfg, reflect.ValueOf(v), av)
|
||||
})
|
||||
return err, true
|
||||
}
|
||||
if u, ok := lhs.Addr().Interface().(Unmarshaler); ok {
|
||||
return u.UnmarshalTOML(unmarshalerSource(av)), true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func unmarshalerSource(av interface{}) []byte {
|
||||
var source []byte
|
||||
switch av := av.(type) {
|
||||
case []*ast.Table:
|
||||
for i, tab := range av {
|
||||
source = append(source, tab.Source()...)
|
||||
if i != len(av)-1 {
|
||||
source = append(source, '\n')
|
||||
}
|
||||
}
|
||||
case ast.Value:
|
||||
source = []byte(av.Source())
|
||||
default:
|
||||
panic(fmt.Sprintf("BUG: unhandled node type %T", av))
|
||||
}
|
||||
return source
|
||||
}
|
||||
|
||||
func setTextUnmarshaler(lhs reflect.Value, val ast.Value) (error, bool) {
|
||||
if !lhs.CanAddr() {
|
||||
return nil, false
|
||||
}
|
||||
u, ok := lhs.Addr().Interface().(encoding.TextUnmarshaler)
|
||||
if !ok || lhs.Type() == timeType {
|
||||
return nil, false
|
||||
}
|
||||
var data string
|
||||
switch val := val.(type) {
|
||||
case *ast.Array:
|
||||
return &unmarshalTypeError{"array", "", lhs.Type()}, true
|
||||
case *ast.String:
|
||||
data = val.Value
|
||||
default:
|
||||
data = val.Source()
|
||||
}
|
||||
return u.UnmarshalText([]byte(data)), true
|
||||
}
|
||||
|
||||
func setInt(fv reflect.Value, v *ast.Integer) error {
|
||||
k := fv.Kind()
|
||||
switch {
|
||||
case k >= reflect.Int && k <= reflect.Int64:
|
||||
i, err := strconv.ParseInt(v.Value, 10, int(fv.Type().Size()*8))
|
||||
if err != nil {
|
||||
return convertNumError(fv.Kind(), err)
|
||||
}
|
||||
fv.SetInt(i)
|
||||
case k >= reflect.Uint && k <= reflect.Uintptr:
|
||||
i, err := strconv.ParseUint(v.Value, 10, int(fv.Type().Size()*8))
|
||||
if err != nil {
|
||||
return convertNumError(fv.Kind(), err)
|
||||
}
|
||||
fv.SetUint(i)
|
||||
case isEface(fv):
|
||||
i, err := strconv.ParseInt(v.Value, 10, 64)
|
||||
if err != nil {
|
||||
return convertNumError(reflect.Int64, err)
|
||||
}
|
||||
fv.Set(reflect.ValueOf(i))
|
||||
default:
|
||||
return &unmarshalTypeError{"integer", "", fv.Type()}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setFloat(fv reflect.Value, v *ast.Float) error {
|
||||
f, err := v.Float()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case fv.Kind() == reflect.Float32 || fv.Kind() == reflect.Float64:
|
||||
if fv.OverflowFloat(f) {
|
||||
return &overflowError{fv.Kind(), v.Value}
|
||||
}
|
||||
fv.SetFloat(f)
|
||||
case isEface(fv):
|
||||
fv.Set(reflect.ValueOf(f))
|
||||
default:
|
||||
return &unmarshalTypeError{"float", "", fv.Type()}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setString(fv reflect.Value, v *ast.String) error {
|
||||
switch {
|
||||
case fv.Kind() == reflect.String:
|
||||
fv.SetString(v.Value)
|
||||
case isEface(fv):
|
||||
fv.Set(reflect.ValueOf(v.Value))
|
||||
default:
|
||||
return &unmarshalTypeError{"string", "", fv.Type()}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setBoolean(fv reflect.Value, v *ast.Boolean) error {
|
||||
b, _ := v.Boolean()
|
||||
switch {
|
||||
case fv.Kind() == reflect.Bool:
|
||||
fv.SetBool(b)
|
||||
case isEface(fv):
|
||||
fv.Set(reflect.ValueOf(b))
|
||||
default:
|
||||
return &unmarshalTypeError{"boolean", "", fv.Type()}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setDatetime(rv reflect.Value, v *ast.Datetime) error {
|
||||
t, err := v.Time()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !timeType.AssignableTo(rv.Type()) {
|
||||
return &unmarshalTypeError{"datetime", "", rv.Type()}
|
||||
}
|
||||
rv.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
|
||||
func setArray(cfg *Config, rv reflect.Value, v *ast.Array) error {
|
||||
var slicetyp reflect.Type
|
||||
switch {
|
||||
case rv.Kind() == reflect.Slice:
|
||||
slicetyp = rv.Type()
|
||||
case isEface(rv):
|
||||
slicetyp = reflect.SliceOf(rv.Type())
|
||||
default:
|
||||
return &unmarshalTypeError{"array", "slice", rv.Type()}
|
||||
}
|
||||
|
||||
if len(v.Value) == 0 {
|
||||
// Ensure defined slices are always set to a non-nil value.
|
||||
rv.Set(reflect.MakeSlice(slicetyp, 0, 0))
|
||||
return nil
|
||||
}
|
||||
|
||||
tomltyp := reflect.TypeOf(v.Value[0])
|
||||
slice := reflect.MakeSlice(slicetyp, len(v.Value), len(v.Value))
|
||||
typ := slicetyp.Elem()
|
||||
for i, vv := range v.Value {
|
||||
if i > 0 && tomltyp != reflect.TypeOf(vv) {
|
||||
return errArrayMultiType
|
||||
}
|
||||
tmp := reflect.New(typ).Elem()
|
||||
if err := setValue(cfg, tmp, vv); err != nil {
|
||||
return err
|
||||
}
|
||||
slice.Index(i).Set(tmp)
|
||||
}
|
||||
rv.Set(slice)
|
||||
return nil
|
||||
}
|
||||
|
||||
func isEface(rv reflect.Value) bool {
|
||||
return rv.Kind() == reflect.Interface && rv.Type().NumMethod() == 0
|
||||
}
|
398
vendor/github.com/naoina/toml/encode.go
generated
vendored
Normal file
398
vendor/github.com/naoina/toml/encode.go
generated
vendored
Normal file
@ -0,0 +1,398 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/naoina/toml/ast"
|
||||
)
|
||||
|
||||
const (
|
||||
tagOmitempty = "omitempty"
|
||||
tagSkip = "-"
|
||||
)
|
||||
|
||||
// Marshal returns the TOML encoding of v.
|
||||
//
|
||||
// Struct values encode as TOML. Each exported struct field becomes a field of
|
||||
// the TOML structure unless
|
||||
// - the field's tag is "-", or
|
||||
// - the field is empty and its tag specifies the "omitempty" option.
|
||||
//
|
||||
// The "toml" key in the struct field's tag value is the key name, followed by
|
||||
// an optional comma and options. Examples:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field int `toml:"-"`
|
||||
//
|
||||
// // Field appears in TOML as key "myName".
|
||||
// Field int `toml:"myName"`
|
||||
//
|
||||
// // Field appears in TOML as key "myName" and the field is omitted from the
|
||||
// // result of encoding if its value is empty.
|
||||
// Field int `toml:"myName,omitempty"`
|
||||
//
|
||||
// // Field appears in TOML as key "field", but the field is skipped if
|
||||
// // empty. Note the leading comma.
|
||||
// Field int `toml:",omitempty"`
|
||||
func (cfg *Config) Marshal(v interface{}) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
err := cfg.NewEncoder(buf).Encode(v)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
// A Encoder writes TOML to an output stream.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
// NewEncoder returns a new Encoder that writes to w.
|
||||
func (cfg *Config) NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{w, cfg}
|
||||
}
|
||||
|
||||
// Encode writes the TOML of v to the stream.
|
||||
// See the documentation for Marshal for details about the conversion of Go values to TOML.
|
||||
func (e *Encoder) Encode(v interface{}) error {
|
||||
rv := reflect.ValueOf(v)
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
return &marshalNilError{rv.Type()}
|
||||
}
|
||||
rv = rv.Elem()
|
||||
}
|
||||
buf := &tableBuf{typ: ast.TableTypeNormal}
|
||||
var err error
|
||||
switch rv.Kind() {
|
||||
case reflect.Struct:
|
||||
err = buf.structFields(e.cfg, rv)
|
||||
case reflect.Map:
|
||||
err = buf.mapFields(e.cfg, rv)
|
||||
default:
|
||||
err = &marshalTableError{rv.Type()}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return buf.writeTo(e.w, "")
|
||||
}
|
||||
|
||||
// Marshaler can be implemented to override the encoding of TOML values. The returned text
|
||||
// must be a simple TOML value (i.e. not a table) and is inserted into marshaler output.
|
||||
//
|
||||
// This interface exists for backwards-compatibility reasons. You probably want to
|
||||
// implement encoding.TextMarshaler or MarshalerRec instead.
|
||||
type Marshaler interface {
|
||||
MarshalTOML() ([]byte, error)
|
||||
}
|
||||
|
||||
// MarshalerRec can be implemented to override the TOML encoding of a type.
|
||||
// The returned value is marshaled in place of the receiver.
|
||||
type MarshalerRec interface {
|
||||
MarshalTOML() (interface{}, error)
|
||||
}
|
||||
|
||||
type tableBuf struct {
|
||||
name string // already escaped / quoted
|
||||
body []byte
|
||||
children []*tableBuf
|
||||
typ ast.TableType
|
||||
arrayDepth int
|
||||
}
|
||||
|
||||
func (b *tableBuf) writeTo(w io.Writer, prefix string) error {
|
||||
key := b.name // TODO: escape dots
|
||||
if prefix != "" {
|
||||
key = prefix + "." + key
|
||||
}
|
||||
|
||||
if b.name != "" {
|
||||
head := "[" + key + "]"
|
||||
if b.typ == ast.TableTypeArray {
|
||||
head = "[" + head + "]"
|
||||
}
|
||||
head += "\n"
|
||||
if _, err := io.WriteString(w, head); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := w.Write(b.body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, child := range b.children {
|
||||
if len(b.body) > 0 || i > 0 {
|
||||
if _, err := w.Write([]byte("\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := child.writeTo(w, key); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *tableBuf) newChild(name string) *tableBuf {
|
||||
child := &tableBuf{name: quoteName(name), typ: ast.TableTypeNormal}
|
||||
if b.arrayDepth > 0 {
|
||||
child.typ = ast.TableTypeArray
|
||||
}
|
||||
return child
|
||||
}
|
||||
|
||||
func (b *tableBuf) addChild(child *tableBuf) {
|
||||
// Empty table elision: we can avoid writing a table that doesn't have any keys on its
|
||||
// own. Array tables can't be elided because they define array elements (which would
|
||||
// be missing if elided).
|
||||
if len(child.body) == 0 && child.typ == ast.TableTypeNormal {
|
||||
for _, gchild := range child.children {
|
||||
gchild.name = child.name + "." + gchild.name
|
||||
b.addChild(gchild)
|
||||
}
|
||||
return
|
||||
}
|
||||
b.children = append(b.children, child)
|
||||
}
|
||||
|
||||
func (b *tableBuf) structFields(cfg *Config, rv reflect.Value) error {
|
||||
rt := rv.Type()
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
ft := rt.Field(i)
|
||||
if ft.PkgPath != "" && !ft.Anonymous { // not exported
|
||||
continue
|
||||
}
|
||||
name, rest := extractTag(ft.Tag.Get(fieldTagName))
|
||||
if name == tagSkip {
|
||||
continue
|
||||
}
|
||||
fv := rv.Field(i)
|
||||
if rest == tagOmitempty && isEmptyValue(fv) {
|
||||
continue
|
||||
}
|
||||
if name == "" {
|
||||
name = cfg.FieldToKey(rt, ft.Name)
|
||||
}
|
||||
if err := b.field(cfg, name, fv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type mapKeyList []struct {
|
||||
key string
|
||||
value reflect.Value
|
||||
}
|
||||
|
||||
func (l mapKeyList) Len() int { return len(l) }
|
||||
func (l mapKeyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
||||
func (l mapKeyList) Less(i, j int) bool { return l[i].key < l[j].key }
|
||||
|
||||
func (b *tableBuf) mapFields(cfg *Config, rv reflect.Value) error {
|
||||
keys := rv.MapKeys()
|
||||
keylist := make(mapKeyList, len(keys))
|
||||
for i, key := range keys {
|
||||
var err error
|
||||
keylist[i].key, err = encodeMapKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keylist[i].value = rv.MapIndex(key)
|
||||
}
|
||||
sort.Sort(keylist)
|
||||
|
||||
for _, kv := range keylist {
|
||||
if err := b.field(cfg, kv.key, kv.value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *tableBuf) field(cfg *Config, name string, rv reflect.Value) error {
|
||||
off := len(b.body)
|
||||
b.body = append(b.body, quoteName(name)...)
|
||||
b.body = append(b.body, " = "...)
|
||||
isTable, err := b.value(cfg, rv, name)
|
||||
if isTable {
|
||||
b.body = b.body[:off] // rub out "key ="
|
||||
} else {
|
||||
b.body = append(b.body, '\n')
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *tableBuf) value(cfg *Config, rv reflect.Value, name string) (bool, error) {
|
||||
isMarshaler, isTable, err := b.marshaler(cfg, rv, name)
|
||||
if isMarshaler {
|
||||
return isTable, err
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
b.body = strconv.AppendInt(b.body, rv.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
b.body = strconv.AppendUint(b.body, rv.Uint(), 10)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
b.body = strconv.AppendFloat(b.body, rv.Float(), 'e', -1, 64)
|
||||
case reflect.Bool:
|
||||
b.body = strconv.AppendBool(b.body, rv.Bool())
|
||||
case reflect.String:
|
||||
b.body = strconv.AppendQuote(b.body, rv.String())
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
if rv.IsNil() {
|
||||
return false, &marshalNilError{rv.Type()}
|
||||
}
|
||||
return b.value(cfg, rv.Elem(), name)
|
||||
case reflect.Slice, reflect.Array:
|
||||
rvlen := rv.Len()
|
||||
if rvlen == 0 {
|
||||
b.body = append(b.body, '[', ']')
|
||||
return false, nil
|
||||
}
|
||||
|
||||
b.arrayDepth++
|
||||
wroteElem := false
|
||||
b.body = append(b.body, '[')
|
||||
for i := 0; i < rvlen; i++ {
|
||||
isTable, err := b.value(cfg, rv.Index(i), name)
|
||||
if err != nil {
|
||||
return isTable, err
|
||||
}
|
||||
wroteElem = wroteElem || !isTable
|
||||
if wroteElem {
|
||||
if i < rvlen-1 {
|
||||
b.body = append(b.body, ',', ' ')
|
||||
} else {
|
||||
b.body = append(b.body, ']')
|
||||
}
|
||||
}
|
||||
}
|
||||
if !wroteElem {
|
||||
b.body = b.body[:len(b.body)-1] // rub out '['
|
||||
}
|
||||
b.arrayDepth--
|
||||
return !wroteElem, nil
|
||||
case reflect.Struct:
|
||||
child := b.newChild(name)
|
||||
err := child.structFields(cfg, rv)
|
||||
b.addChild(child)
|
||||
return true, err
|
||||
case reflect.Map:
|
||||
child := b.newChild(name)
|
||||
err := child.mapFields(cfg, rv)
|
||||
b.addChild(child)
|
||||
return true, err
|
||||
default:
|
||||
return false, fmt.Errorf("toml: marshal: unsupported type %v", rv.Kind())
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (b *tableBuf) marshaler(cfg *Config, rv reflect.Value, name string) (handled, isTable bool, err error) {
|
||||
switch t := rv.Interface().(type) {
|
||||
case encoding.TextMarshaler:
|
||||
enc, err := t.MarshalText()
|
||||
if err != nil {
|
||||
return true, false, err
|
||||
}
|
||||
b.body = encodeTextMarshaler(b.body, string(enc))
|
||||
return true, false, nil
|
||||
case MarshalerRec:
|
||||
newval, err := t.MarshalTOML()
|
||||
if err != nil {
|
||||
return true, false, err
|
||||
}
|
||||
isTable, err = b.value(cfg, reflect.ValueOf(newval), name)
|
||||
return true, isTable, err
|
||||
case Marshaler:
|
||||
enc, err := t.MarshalTOML()
|
||||
if err != nil {
|
||||
return true, false, err
|
||||
}
|
||||
b.body = append(b.body, enc...)
|
||||
return true, false, nil
|
||||
}
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
func encodeTextMarshaler(buf []byte, v string) []byte {
|
||||
// Emit the value without quotes if possible.
|
||||
if v == "true" || v == "false" {
|
||||
return append(buf, v...)
|
||||
} else if _, err := time.Parse(time.RFC3339Nano, v); err == nil {
|
||||
return append(buf, v...)
|
||||
} else if _, err := strconv.ParseInt(v, 10, 64); err == nil {
|
||||
return append(buf, v...)
|
||||
} else if _, err := strconv.ParseUint(v, 10, 64); err == nil {
|
||||
return append(buf, v...)
|
||||
} else if _, err := strconv.ParseFloat(v, 64); err == nil {
|
||||
return append(buf, v...)
|
||||
}
|
||||
return strconv.AppendQuote(buf, v)
|
||||
}
|
||||
|
||||
func encodeMapKey(rv reflect.Value) (string, error) {
|
||||
if rv.Kind() == reflect.String {
|
||||
return rv.String(), nil
|
||||
}
|
||||
if tm, ok := rv.Interface().(encoding.TextMarshaler); ok {
|
||||
b, err := tm.MarshalText()
|
||||
return string(b), err
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(rv.Int(), 10), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return strconv.FormatUint(rv.Uint(), 10), nil
|
||||
}
|
||||
return "", fmt.Errorf("toml: invalid map key type %v", rv.Type())
|
||||
}
|
||||
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array:
|
||||
// encoding/json treats all arrays with non-zero length as non-empty. We check the
|
||||
// array content here because zero-length arrays are almost never used.
|
||||
len := v.Len()
|
||||
for i := 0; i < len; i++ {
|
||||
if !isEmptyValue(v.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func quoteName(s string) string {
|
||||
if len(s) == 0 {
|
||||
return strconv.Quote(s)
|
||||
}
|
||||
for _, r := range s {
|
||||
if r >= '0' && r <= '9' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z' || r == '-' || r == '_' {
|
||||
continue
|
||||
}
|
||||
return strconv.Quote(s)
|
||||
}
|
||||
return s
|
||||
}
|
107
vendor/github.com/naoina/toml/error.go
generated
vendored
Normal file
107
vendor/github.com/naoina/toml/error.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
errArrayMultiType = errors.New("array can't contain multiple types")
|
||||
)
|
||||
|
||||
// LineError is returned by Unmarshal, UnmarshalTable and Parse
|
||||
// if the error is local to a line.
|
||||
type LineError struct {
|
||||
Line int
|
||||
StructField string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (err *LineError) Error() string {
|
||||
field := ""
|
||||
if err.StructField != "" {
|
||||
field = "(" + err.StructField + ") "
|
||||
}
|
||||
return fmt.Sprintf("line %d: %s%v", err.Line, field, err.Err)
|
||||
}
|
||||
|
||||
func lineError(line int, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := err.(*LineError); ok {
|
||||
return err
|
||||
}
|
||||
return &LineError{Line: line, Err: err}
|
||||
}
|
||||
|
||||
func lineErrorField(line int, field string, err error) error {
|
||||
if lerr, ok := err.(*LineError); ok {
|
||||
return lerr
|
||||
} else if err != nil {
|
||||
err = &LineError{Line: line, StructField: field, Err: err}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type overflowError struct {
|
||||
kind reflect.Kind
|
||||
v string
|
||||
}
|
||||
|
||||
func (err *overflowError) Error() string {
|
||||
return fmt.Sprintf("value %s is out of range for %v", err.v, err.kind)
|
||||
}
|
||||
|
||||
func convertNumError(kind reflect.Kind, err error) error {
|
||||
if numerr, ok := err.(*strconv.NumError); ok && numerr.Err == strconv.ErrRange {
|
||||
return &overflowError{kind, numerr.Num}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type invalidUnmarshalError struct {
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (err *invalidUnmarshalError) Error() string {
|
||||
if err.typ == nil {
|
||||
return "toml: Unmarshal(nil)"
|
||||
}
|
||||
if err.typ.Kind() != reflect.Ptr {
|
||||
return "toml: Unmarshal(non-pointer " + err.typ.String() + ")"
|
||||
}
|
||||
return "toml: Unmarshal(nil " + err.typ.String() + ")"
|
||||
}
|
||||
|
||||
type unmarshalTypeError struct {
|
||||
what string
|
||||
want string
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (err *unmarshalTypeError) Error() string {
|
||||
msg := fmt.Sprintf("cannot unmarshal TOML %s into %s", err.what, err.typ)
|
||||
if err.want != "" {
|
||||
msg += " (need " + err.want + ")"
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
type marshalNilError struct {
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (err *marshalNilError) Error() string {
|
||||
return fmt.Sprintf("toml: cannot marshal nil %s", err.typ)
|
||||
}
|
||||
|
||||
type marshalTableError struct {
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (err *marshalTableError) Error() string {
|
||||
return fmt.Sprintf("toml: cannot marshal %s as table, want struct or map type", err.typ)
|
||||
}
|
376
vendor/github.com/naoina/toml/parse.go
generated
vendored
Normal file
376
vendor/github.com/naoina/toml/parse.go
generated
vendored
Normal file
@ -0,0 +1,376 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/naoina/toml/ast"
|
||||
)
|
||||
|
||||
// The parser is generated by github.com/pointlander/peg. To regenerate it, do:
|
||||
//
|
||||
// go get -u github.com/pointlander/peg
|
||||
// go generate .
|
||||
|
||||
//go:generate peg -switch -inline parse.peg
|
||||
|
||||
var errParse = errors.New("invalid TOML syntax")
|
||||
|
||||
// Parse returns an AST representation of TOML.
|
||||
// The toplevel is represented by a table.
|
||||
func Parse(data []byte) (*ast.Table, error) {
|
||||
d := &parseState{p: &tomlParser{Buffer: string(data)}}
|
||||
d.init()
|
||||
|
||||
if err := d.parse(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d.p.toml.table, nil
|
||||
}
|
||||
|
||||
type parseState struct {
|
||||
p *tomlParser
|
||||
}
|
||||
|
||||
func (d *parseState) init() {
|
||||
d.p.Init()
|
||||
d.p.toml.init(d.p.buffer)
|
||||
}
|
||||
|
||||
func (d *parseState) parse() error {
|
||||
if err := d.p.Parse(); err != nil {
|
||||
if err, ok := err.(*parseError); ok {
|
||||
return lineError(err.Line(), errParse)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return d.execute()
|
||||
}
|
||||
|
||||
func (d *parseState) execute() (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
lerr, ok := e.(*LineError)
|
||||
if !ok {
|
||||
panic(e)
|
||||
}
|
||||
err = lerr
|
||||
}
|
||||
}()
|
||||
d.p.Execute()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *parseError) Line() int {
|
||||
tokens := []token32{e.max}
|
||||
positions, p := make([]int, 2*len(tokens)), 0
|
||||
for _, token := range tokens {
|
||||
positions[p], p = int(token.begin), p+1
|
||||
positions[p], p = int(token.end), p+1
|
||||
}
|
||||
for _, t := range translatePositions(e.p.buffer, positions) {
|
||||
if e.p.line < t.line {
|
||||
e.p.line = t.line
|
||||
}
|
||||
}
|
||||
return e.p.line
|
||||
}
|
||||
|
||||
type stack struct {
|
||||
key string
|
||||
table *ast.Table
|
||||
}
|
||||
|
||||
type array struct {
|
||||
parent *array
|
||||
child *array
|
||||
current *ast.Array
|
||||
line int
|
||||
}
|
||||
|
||||
type toml struct {
|
||||
table *ast.Table
|
||||
line int
|
||||
currentTable *ast.Table
|
||||
s string
|
||||
key string
|
||||
val ast.Value
|
||||
arr *array
|
||||
stack []*stack
|
||||
skip bool
|
||||
}
|
||||
|
||||
func (p *toml) init(data []rune) {
|
||||
p.line = 1
|
||||
p.table = p.newTable(ast.TableTypeNormal, "")
|
||||
p.table.Position.End = len(data) - 1
|
||||
p.table.Data = data[:len(data)-1] // truncate the end_symbol added by PEG parse generator.
|
||||
p.currentTable = p.table
|
||||
}
|
||||
|
||||
func (p *toml) Error(err error) {
|
||||
panic(lineError(p.line, err))
|
||||
}
|
||||
|
||||
func (p *tomlParser) SetTime(begin, end int) {
|
||||
p.val = &ast.Datetime{
|
||||
Position: ast.Position{Begin: begin, End: end},
|
||||
Data: p.buffer[begin:end],
|
||||
Value: string(p.buffer[begin:end]),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tomlParser) SetFloat64(begin, end int) {
|
||||
p.val = &ast.Float{
|
||||
Position: ast.Position{Begin: begin, End: end},
|
||||
Data: p.buffer[begin:end],
|
||||
Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tomlParser) SetInt64(begin, end int) {
|
||||
p.val = &ast.Integer{
|
||||
Position: ast.Position{Begin: begin, End: end},
|
||||
Data: p.buffer[begin:end],
|
||||
Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tomlParser) SetString(begin, end int) {
|
||||
p.val = &ast.String{
|
||||
Position: ast.Position{Begin: begin, End: end},
|
||||
Data: p.buffer[begin:end],
|
||||
Value: p.s,
|
||||
}
|
||||
p.s = ""
|
||||
}
|
||||
|
||||
func (p *tomlParser) SetBool(begin, end int) {
|
||||
p.val = &ast.Boolean{
|
||||
Position: ast.Position{Begin: begin, End: end},
|
||||
Data: p.buffer[begin:end],
|
||||
Value: string(p.buffer[begin:end]),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tomlParser) StartArray() {
|
||||
if p.arr == nil {
|
||||
p.arr = &array{line: p.line, current: &ast.Array{}}
|
||||
return
|
||||
}
|
||||
p.arr.child = &array{parent: p.arr, line: p.line, current: &ast.Array{}}
|
||||
p.arr = p.arr.child
|
||||
}
|
||||
|
||||
func (p *tomlParser) AddArrayVal() {
|
||||
if p.arr.current == nil {
|
||||
p.arr.current = &ast.Array{}
|
||||
}
|
||||
p.arr.current.Value = append(p.arr.current.Value, p.val)
|
||||
}
|
||||
|
||||
func (p *tomlParser) SetArray(begin, end int) {
|
||||
p.arr.current.Position = ast.Position{Begin: begin, End: end}
|
||||
p.arr.current.Data = p.buffer[begin:end]
|
||||
p.val = p.arr.current
|
||||
p.arr = p.arr.parent
|
||||
}
|
||||
|
||||
func (p *toml) SetTable(buf []rune, begin, end int) {
|
||||
p.setTable(p.table, buf, begin, end)
|
||||
}
|
||||
|
||||
func (p *toml) setTable(parent *ast.Table, buf []rune, begin, end int) {
|
||||
name := string(buf[begin:end])
|
||||
names := splitTableKey(name)
|
||||
parent, err := p.lookupTable(parent, names[:len(names)-1])
|
||||
if err != nil {
|
||||
p.Error(err)
|
||||
}
|
||||
last := names[len(names)-1]
|
||||
tbl := p.newTable(ast.TableTypeNormal, last)
|
||||
switch v := parent.Fields[last].(type) {
|
||||
case nil:
|
||||
parent.Fields[last] = tbl
|
||||
case []*ast.Table:
|
||||
p.Error(fmt.Errorf("table `%s' is in conflict with array table in line %d", name, v[0].Line))
|
||||
case *ast.Table:
|
||||
if (v.Position == ast.Position{}) {
|
||||
// This table was created as an implicit parent.
|
||||
// Replace it with the real defined table.
|
||||
tbl.Fields = v.Fields
|
||||
parent.Fields[last] = tbl
|
||||
} else {
|
||||
p.Error(fmt.Errorf("table `%s' is in conflict with table in line %d", name, v.Line))
|
||||
}
|
||||
case *ast.KeyValue:
|
||||
p.Error(fmt.Errorf("table `%s' is in conflict with line %d", name, v.Line))
|
||||
default:
|
||||
p.Error(fmt.Errorf("BUG: table `%s' is in conflict but it's unknown type `%T'", last, v))
|
||||
}
|
||||
p.currentTable = tbl
|
||||
}
|
||||
|
||||
func (p *toml) newTable(typ ast.TableType, name string) *ast.Table {
|
||||
return &ast.Table{
|
||||
Line: p.line,
|
||||
Name: name,
|
||||
Type: typ,
|
||||
Fields: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tomlParser) SetTableString(begin, end int) {
|
||||
p.currentTable.Data = p.buffer[begin:end]
|
||||
p.currentTable.Position.Begin = begin
|
||||
p.currentTable.Position.End = end
|
||||
}
|
||||
|
||||
func (p *toml) SetArrayTable(buf []rune, begin, end int) {
|
||||
p.setArrayTable(p.table, buf, begin, end)
|
||||
}
|
||||
|
||||
func (p *toml) setArrayTable(parent *ast.Table, buf []rune, begin, end int) {
|
||||
name := string(buf[begin:end])
|
||||
names := splitTableKey(name)
|
||||
parent, err := p.lookupTable(parent, names[:len(names)-1])
|
||||
if err != nil {
|
||||
p.Error(err)
|
||||
}
|
||||
last := names[len(names)-1]
|
||||
tbl := p.newTable(ast.TableTypeArray, last)
|
||||
switch v := parent.Fields[last].(type) {
|
||||
case nil:
|
||||
parent.Fields[last] = []*ast.Table{tbl}
|
||||
case []*ast.Table:
|
||||
parent.Fields[last] = append(v, tbl)
|
||||
case *ast.Table:
|
||||
p.Error(fmt.Errorf("array table `%s' is in conflict with table in line %d", name, v.Line))
|
||||
case *ast.KeyValue:
|
||||
p.Error(fmt.Errorf("array table `%s' is in conflict with line %d", name, v.Line))
|
||||
default:
|
||||
p.Error(fmt.Errorf("BUG: array table `%s' is in conflict but it's unknown type `%T'", name, v))
|
||||
}
|
||||
p.currentTable = tbl
|
||||
}
|
||||
|
||||
func (p *toml) StartInlineTable() {
|
||||
p.skip = false
|
||||
p.stack = append(p.stack, &stack{p.key, p.currentTable})
|
||||
buf := []rune(p.key)
|
||||
if p.arr == nil {
|
||||
p.setTable(p.currentTable, buf, 0, len(buf))
|
||||
} else {
|
||||
p.setArrayTable(p.currentTable, buf, 0, len(buf))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *toml) EndInlineTable() {
|
||||
st := p.stack[len(p.stack)-1]
|
||||
p.key, p.currentTable = st.key, st.table
|
||||
p.stack[len(p.stack)-1] = nil
|
||||
p.stack = p.stack[:len(p.stack)-1]
|
||||
p.skip = true
|
||||
}
|
||||
|
||||
func (p *toml) AddLineCount(i int) {
|
||||
p.line += i
|
||||
}
|
||||
|
||||
func (p *toml) SetKey(buf []rune, begin, end int) {
|
||||
p.key = string(buf[begin:end])
|
||||
}
|
||||
|
||||
func (p *toml) AddKeyValue() {
|
||||
if p.skip {
|
||||
p.skip = false
|
||||
return
|
||||
}
|
||||
if val, exists := p.currentTable.Fields[p.key]; exists {
|
||||
switch v := val.(type) {
|
||||
case *ast.Table:
|
||||
p.Error(fmt.Errorf("key `%s' is in conflict with table in line %d", p.key, v.Line))
|
||||
case *ast.KeyValue:
|
||||
p.Error(fmt.Errorf("key `%s' is in conflict with line %xd", p.key, v.Line))
|
||||
default:
|
||||
p.Error(fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", p.key, v))
|
||||
}
|
||||
}
|
||||
p.currentTable.Fields[p.key] = &ast.KeyValue{Key: p.key, Value: p.val, Line: p.line}
|
||||
}
|
||||
|
||||
func (p *toml) SetBasicString(buf []rune, begin, end int) {
|
||||
p.s = p.unquote(string(buf[begin:end]))
|
||||
}
|
||||
|
||||
func (p *toml) SetMultilineString() {
|
||||
p.s = p.unquote(`"` + escapeReplacer.Replace(strings.TrimLeft(p.s, "\r\n")) + `"`)
|
||||
}
|
||||
|
||||
func (p *toml) AddMultilineBasicBody(buf []rune, begin, end int) {
|
||||
p.s += string(buf[begin:end])
|
||||
}
|
||||
|
||||
func (p *toml) SetLiteralString(buf []rune, begin, end int) {
|
||||
p.s = string(buf[begin:end])
|
||||
}
|
||||
|
||||
func (p *toml) SetMultilineLiteralString(buf []rune, begin, end int) {
|
||||
p.s = strings.TrimLeft(string(buf[begin:end]), "\r\n")
|
||||
}
|
||||
|
||||
func (p *toml) unquote(s string) string {
|
||||
s, err := strconv.Unquote(s)
|
||||
if err != nil {
|
||||
p.Error(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (p *toml) lookupTable(t *ast.Table, keys []string) (*ast.Table, error) {
|
||||
for _, s := range keys {
|
||||
val, exists := t.Fields[s]
|
||||
if !exists {
|
||||
tbl := p.newTable(ast.TableTypeNormal, s)
|
||||
t.Fields[s] = tbl
|
||||
t = tbl
|
||||
continue
|
||||
}
|
||||
switch v := val.(type) {
|
||||
case *ast.Table:
|
||||
t = v
|
||||
case []*ast.Table:
|
||||
t = v[len(v)-1]
|
||||
case *ast.KeyValue:
|
||||
return nil, fmt.Errorf("key `%s' is in conflict with line %d", s, v.Line)
|
||||
default:
|
||||
return nil, fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", s, v)
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func splitTableKey(tk string) []string {
|
||||
key := make([]byte, 0, 1)
|
||||
keys := make([]string, 0, 1)
|
||||
inQuote := false
|
||||
for i := 0; i < len(tk); i++ {
|
||||
k := tk[i]
|
||||
switch {
|
||||
case k == tableSeparator && !inQuote:
|
||||
keys = append(keys, string(key))
|
||||
key = key[:0] // reuse buffer.
|
||||
case k == '"':
|
||||
inQuote = !inQuote
|
||||
case (k == ' ' || k == '\t') && !inQuote:
|
||||
// skip.
|
||||
default:
|
||||
key = append(key, k)
|
||||
}
|
||||
}
|
||||
keys = append(keys, string(key))
|
||||
return keys
|
||||
}
|
145
vendor/github.com/naoina/toml/parse.peg
generated
vendored
Normal file
145
vendor/github.com/naoina/toml/parse.peg
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
package toml
|
||||
|
||||
type tomlParser Peg {
|
||||
toml
|
||||
}
|
||||
|
||||
TOML <- Expression (newline Expression)* newline? !. { _ = buffer }
|
||||
|
||||
Expression <- (
|
||||
<ws table ws comment? (wsnl keyval ws comment?)*> { p.SetTableString(begin, end) }
|
||||
/ ws keyval ws comment?
|
||||
/ ws comment?
|
||||
/ ws
|
||||
)
|
||||
|
||||
newline <- <[\r\n]+> { p.AddLineCount(end - begin) }
|
||||
|
||||
ws <- [ \t]*
|
||||
wsnl <- (
|
||||
[ \t]
|
||||
/ <[\r\n]> { p.AddLineCount(end - begin) }
|
||||
)*
|
||||
|
||||
comment <- '#' <[\t -\0x10FFFF]*>
|
||||
|
||||
keyval <- key ws '=' ws val { p.AddKeyValue() }
|
||||
|
||||
key <- bareKey / quotedKey
|
||||
|
||||
bareKey <- <[0-9A-Za-z\-_]+> { p.SetKey(p.buffer, begin, end) }
|
||||
|
||||
quotedKey <- '"' <basicChar+> '"' { p.SetKey(p.buffer, begin-1, end+1) }
|
||||
|
||||
val <- (
|
||||
<datetime> { p.SetTime(begin, end) }
|
||||
/ <float> { p.SetFloat64(begin, end) }
|
||||
/ <integer> { p.SetInt64(begin, end) }
|
||||
/ <string> { p.SetString(begin, end) }
|
||||
/ <boolean> { p.SetBool(begin, end) }
|
||||
/ <array> { p.SetArray(begin, end) }
|
||||
/ inlineTable
|
||||
)
|
||||
|
||||
table <- stdTable / arrayTable
|
||||
|
||||
stdTable <- '[' ws <tableKey> ws ']' { p.SetTable(p.buffer, begin, end) }
|
||||
|
||||
arrayTable <- '[[' ws <tableKey> ws ']]' { p.SetArrayTable(p.buffer, begin, end) }
|
||||
|
||||
inlineTable <- (
|
||||
'{' { p.StartInlineTable() }
|
||||
ws inlineTableKeyValues ws
|
||||
'}' { p.EndInlineTable() }
|
||||
)
|
||||
|
||||
inlineTableKeyValues <- (keyval inlineTableValSep?)*
|
||||
|
||||
tableKey <- key (tableKeySep key)*
|
||||
|
||||
tableKeySep <- ws '.' ws
|
||||
|
||||
inlineTableValSep <- ws ',' ws
|
||||
|
||||
integer <- [\-+]? int
|
||||
int <- [1-9] (digit / '_' digit)+ / digit
|
||||
|
||||
float <- integer (frac exp? / frac? exp)
|
||||
frac <- '.' digit (digit / '_' digit)*
|
||||
exp <- [eE] [\-+]? digit (digit / '_' digit)*
|
||||
|
||||
string <- (
|
||||
mlLiteralString
|
||||
/ literalString
|
||||
/ mlBasicString
|
||||
/ basicString
|
||||
)
|
||||
|
||||
basicString <- <'"' basicChar* '"'> { p.SetBasicString(p.buffer, begin, end) }
|
||||
|
||||
basicChar <- basicUnescaped / escaped
|
||||
escaped <- escape ([btnfr"/\\] / 'u' hexQuad / 'U' hexQuad hexQuad)
|
||||
|
||||
basicUnescaped <- [ -!#-\[\]-\0x10FFFF]
|
||||
|
||||
escape <- '\\'
|
||||
|
||||
mlBasicString <- '"""' mlBasicBody '"""' { p.SetMultilineString() }
|
||||
|
||||
mlBasicBody <- (
|
||||
<basicChar / newline> { p.AddMultilineBasicBody(p.buffer, begin, end) }
|
||||
/ escape newline wsnl
|
||||
)*
|
||||
|
||||
literalString <- "'" <literalChar*> "'" { p.SetLiteralString(p.buffer, begin, end) }
|
||||
|
||||
literalChar <- [\t -&(-\0x10FFFF]
|
||||
|
||||
mlLiteralString <- "'''" <mlLiteralBody> "'''" { p.SetMultilineLiteralString(p.buffer, begin, end) }
|
||||
|
||||
mlLiteralBody <- (!"'''" (mlLiteralChar / newline))*
|
||||
|
||||
mlLiteralChar <- [\t -\0x10FFFF]
|
||||
|
||||
hexdigit <- [0-9A-Fa-f]
|
||||
hexQuad <- hexdigit hexdigit hexdigit hexdigit
|
||||
|
||||
boolean <- 'true' / 'false'
|
||||
|
||||
dateFullYear <- digitQuad
|
||||
dateMonth <- digitDual
|
||||
dateMDay <- digitDual
|
||||
timeHour <- digitDual
|
||||
timeMinute <- digitDual
|
||||
timeSecond <- digitDual
|
||||
timeSecfrac <- '.' digit+
|
||||
timeNumoffset <- [\-+] timeHour ':' timeMinute
|
||||
timeOffset <- 'Z' / timeNumoffset
|
||||
partialTime <- timeHour ':' timeMinute ':' timeSecond timeSecfrac?
|
||||
fullDate <- dateFullYear '-' dateMonth '-' dateMDay
|
||||
fullTime <- partialTime timeOffset
|
||||
datetime <- (fullDate ('T' fullTime)?) / partialTime
|
||||
|
||||
digit <- [0-9]
|
||||
digitDual <- digit digit
|
||||
digitQuad <- digitDual digitDual
|
||||
|
||||
array <- (
|
||||
'[' { p.StartArray() }
|
||||
wsnl arrayValues? wsnl
|
||||
']'
|
||||
)
|
||||
|
||||
arrayValues <- (
|
||||
val { p.AddArrayVal() }
|
||||
(
|
||||
wsnl comment?
|
||||
wsnl arraySep
|
||||
wsnl comment?
|
||||
wsnl val { p.AddArrayVal() }
|
||||
)*
|
||||
wsnl arraySep?
|
||||
wsnl comment?
|
||||
)
|
||||
|
||||
arraySep <- ','
|
2556
vendor/github.com/naoina/toml/parse.peg.go
generated
vendored
Normal file
2556
vendor/github.com/naoina/toml/parse.peg.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
65
vendor/github.com/naoina/toml/util.go
generated
vendored
Normal file
65
vendor/github.com/naoina/toml/util.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const fieldTagName = "toml"
|
||||
|
||||
// fieldCache maps normalized field names to their position in a struct.
|
||||
type fieldCache struct {
|
||||
named map[string]fieldInfo // fields with an explicit name in tag
|
||||
auto map[string]fieldInfo // fields with auto-assigned normalized names
|
||||
}
|
||||
|
||||
type fieldInfo struct {
|
||||
index []int
|
||||
name string
|
||||
ignored bool
|
||||
}
|
||||
|
||||
func makeFieldCache(cfg *Config, rt reflect.Type) fieldCache {
|
||||
named, auto := make(map[string]fieldInfo), make(map[string]fieldInfo)
|
||||
for i := 0; i < rt.NumField(); i++ {
|
||||
ft := rt.Field(i)
|
||||
// skip unexported fields
|
||||
if ft.PkgPath != "" && !ft.Anonymous {
|
||||
continue
|
||||
}
|
||||
col, _ := extractTag(ft.Tag.Get(fieldTagName))
|
||||
info := fieldInfo{index: ft.Index, name: ft.Name, ignored: col == "-"}
|
||||
if col == "" || col == "-" {
|
||||
auto[cfg.NormFieldName(rt, ft.Name)] = info
|
||||
} else {
|
||||
named[col] = info
|
||||
}
|
||||
}
|
||||
return fieldCache{named, auto}
|
||||
}
|
||||
|
||||
func (fc fieldCache) findField(cfg *Config, rv reflect.Value, name string) (reflect.Value, string, error) {
|
||||
info, found := fc.named[name]
|
||||
if !found {
|
||||
info, found = fc.auto[cfg.NormFieldName(rv.Type(), name)]
|
||||
}
|
||||
if !found {
|
||||
if cfg.MissingField == nil {
|
||||
return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' is not defined in %v", name, rv.Type())
|
||||
} else {
|
||||
return reflect.Value{}, "", cfg.MissingField(rv.Type(), name)
|
||||
}
|
||||
} else if info.ignored {
|
||||
return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' in %v cannot be set through TOML", name, rv.Type())
|
||||
}
|
||||
return rv.FieldByIndex(info.index), info.name, nil
|
||||
}
|
||||
|
||||
func extractTag(tag string) (col, rest string) {
|
||||
tags := strings.SplitN(tag, ",", 2)
|
||||
if len(tags) == 2 {
|
||||
return strings.TrimSpace(tags[0]), strings.TrimSpace(tags[1])
|
||||
}
|
||||
return strings.TrimSpace(tags[0]), ""
|
||||
}
|
Reference in New Issue
Block a user