b95dd6a380
Change-Id: Ifa8cc0e4abb798c63c9d4ac9297e3e32443125e4 Implements: blueprint auth-controller-framework Signed-off-by: mozhuli <21621232@zju.edu.cn>
239 lines
5.6 KiB
Go
239 lines
5.6 KiB
Go
package gcfg
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
|
|
"gopkg.in/gcfg.v1/scanner"
|
|
"gopkg.in/gcfg.v1/token"
|
|
"gopkg.in/warnings.v0"
|
|
)
|
|
|
|
var unescape = map[rune]rune{'\\': '\\', '"': '"', 'n': '\n', 't': '\t'}
|
|
|
|
// no error: invalid literals should be caught by scanner
|
|
func unquote(s string) string {
|
|
u, q, esc := make([]rune, 0, len(s)), false, false
|
|
for _, c := range s {
|
|
if esc {
|
|
uc, ok := unescape[c]
|
|
switch {
|
|
case ok:
|
|
u = append(u, uc)
|
|
fallthrough
|
|
case !q && c == '\n':
|
|
esc = false
|
|
continue
|
|
}
|
|
panic("invalid escape sequence")
|
|
}
|
|
switch c {
|
|
case '"':
|
|
q = !q
|
|
case '\\':
|
|
esc = true
|
|
default:
|
|
u = append(u, c)
|
|
}
|
|
}
|
|
if q {
|
|
panic("missing end quote")
|
|
}
|
|
if esc {
|
|
panic("invalid escape sequence")
|
|
}
|
|
return string(u)
|
|
}
|
|
|
|
func readIntoPass(c *warnings.Collector, config interface{}, fset *token.FileSet,
|
|
file *token.File, src []byte, subsectPass bool) error {
|
|
//
|
|
var s scanner.Scanner
|
|
var errs scanner.ErrorList
|
|
s.Init(file, src, func(p token.Position, m string) { errs.Add(p, m) }, 0)
|
|
sect, sectsub := "", ""
|
|
pos, tok, lit := s.Scan()
|
|
errfn := func(msg string) error {
|
|
return fmt.Errorf("%s: %s", fset.Position(pos), msg)
|
|
}
|
|
for {
|
|
if errs.Len() > 0 {
|
|
if err := c.Collect(errs.Err()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
switch tok {
|
|
case token.EOF:
|
|
return nil
|
|
case token.EOL, token.COMMENT:
|
|
pos, tok, lit = s.Scan()
|
|
case token.LBRACK:
|
|
pos, tok, lit = s.Scan()
|
|
if errs.Len() > 0 {
|
|
if err := c.Collect(errs.Err()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if tok != token.IDENT {
|
|
if err := c.Collect(errfn("expected section name")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
sect, sectsub = lit, ""
|
|
pos, tok, lit = s.Scan()
|
|
if errs.Len() > 0 {
|
|
if err := c.Collect(errs.Err()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if tok == token.STRING {
|
|
sectsub = unquote(lit)
|
|
if sectsub == "" {
|
|
if err := c.Collect(errfn("empty subsection name")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
pos, tok, lit = s.Scan()
|
|
if errs.Len() > 0 {
|
|
if err := c.Collect(errs.Err()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if tok != token.RBRACK {
|
|
if sectsub == "" {
|
|
if err := c.Collect(errfn("expected subsection name or right bracket")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := c.Collect(errfn("expected right bracket")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
pos, tok, lit = s.Scan()
|
|
if tok != token.EOL && tok != token.EOF && tok != token.COMMENT {
|
|
if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// If a section/subsection header was found, ensure a
|
|
// container object is created, even if there are no
|
|
// variables further down.
|
|
err := c.Collect(set(c, config, sect, sectsub, "", true, "", subsectPass))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case token.IDENT:
|
|
if sect == "" {
|
|
if err := c.Collect(errfn("expected section header")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
n := lit
|
|
pos, tok, lit = s.Scan()
|
|
if errs.Len() > 0 {
|
|
return errs.Err()
|
|
}
|
|
blank, v := tok == token.EOF || tok == token.EOL || tok == token.COMMENT, ""
|
|
if !blank {
|
|
if tok != token.ASSIGN {
|
|
if err := c.Collect(errfn("expected '='")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
pos, tok, lit = s.Scan()
|
|
if errs.Len() > 0 {
|
|
if err := c.Collect(errs.Err()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if tok != token.STRING {
|
|
if err := c.Collect(errfn("expected value")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
v = unquote(lit)
|
|
pos, tok, lit = s.Scan()
|
|
if errs.Len() > 0 {
|
|
if err := c.Collect(errs.Err()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if tok != token.EOL && tok != token.EOF && tok != token.COMMENT {
|
|
if err := c.Collect(errfn("expected EOL, EOF, or comment")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
err := set(c, config, sect, sectsub, n, blank, v, subsectPass)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
if sect == "" {
|
|
if err := c.Collect(errfn("expected section header")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := c.Collect(errfn("expected section header or variable declaration")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
panic("never reached")
|
|
}
|
|
|
|
func readInto(config interface{}, fset *token.FileSet, file *token.File,
|
|
src []byte) error {
|
|
//
|
|
c := warnings.NewCollector(isFatal)
|
|
err := readIntoPass(c, config, fset, file, src, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = readIntoPass(c, config, fset, file, src, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Done()
|
|
}
|
|
|
|
// ReadInto reads gcfg formatted data from reader and sets the values into the
|
|
// corresponding fields in config.
|
|
func ReadInto(config interface{}, reader io.Reader) error {
|
|
src, err := ioutil.ReadAll(reader)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fset := token.NewFileSet()
|
|
file := fset.AddFile("", fset.Base(), len(src))
|
|
return readInto(config, fset, file, src)
|
|
}
|
|
|
|
// ReadStringInto reads gcfg formatted data from str and sets the values into
|
|
// the corresponding fields in config.
|
|
func ReadStringInto(config interface{}, str string) error {
|
|
r := strings.NewReader(str)
|
|
return ReadInto(config, r)
|
|
}
|
|
|
|
// ReadFileInto reads gcfg formatted data from the file filename and sets the
|
|
// values into the corresponding fields in config.
|
|
func ReadFileInto(config interface{}, filename string) error {
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
src, err := ioutil.ReadAll(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fset := token.NewFileSet()
|
|
file := fset.AddFile(filename, fset.Base(), len(src))
|
|
return readInto(config, fset, file, src)
|
|
}
|