mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-03 23:40:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			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)
 | 
						|
}
 |