1
1
mirror of https://git.sr.ht/~emersion/tlstunnel synced 2024-11-19 15:53:50 +01:00
tlstunnel/config.go
Simon Ser ec2a768909
Move executable to cmd/tlstunnel
This allows us to expose the toplevel tlstunnel package.
2020-09-10 14:49:59 +02:00

110 lines
2.1 KiB
Go

package tlstunnel
import (
"bufio"
"fmt"
"io"
"os"
"github.com/google/shlex"
)
type Directive struct {
Name string
Params []string
Children []*Directive
}
func (d *Directive) ParseParams(params ...*string) error {
if len(d.Params) < len(params) {
return fmt.Errorf("directive %q: want %v params, got %v", d.Name, len(params), len(d.Params))
}
for i, ptr := range params {
if ptr == nil {
continue
}
*ptr = d.Params[i]
}
return nil
}
func (d *Directive) ChildrenByName(name string) []*Directive {
l := make([]*Directive, 0, len(d.Children))
for _, child := range d.Children {
if child.Name == name {
l = append(l, child)
}
}
return l
}
func (d *Directive) ChildByName(name string) *Directive {
for _, child := range d.Children {
if child.Name == name {
return child
}
}
return nil
}
func LoadConfig(path string) (*Directive, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return ParseConfig(f)
}
func ParseConfig(r io.Reader) (*Directive, error) {
scanner := bufio.NewScanner(r)
var directives []*Directive
var cur *Directive
for scanner.Scan() {
l := scanner.Text()
words, err := shlex.Split(l)
if err != nil {
return nil, fmt.Errorf("failed to parse config file: %v", err)
} else if len(words) == 0 {
continue
}
if len(words) == 1 && l[len(l)-1] == '}' {
if cur == nil {
return nil, fmt.Errorf("unexpected '}'")
}
cur = nil
continue
}
var d *Directive
if words[len(words)-1] == "{" && l[len(l)-1] == '{' {
words = words[:len(words)-1]
var name string
params := words
if len(words) > 0 {
name, params = words[0], words[1:]
}
d = &Directive{Name: name, Params: params}
cur = d
directives = append(directives, d)
} else {
d = &Directive{Name: words[0], Params: words[1:]}
if cur != nil {
cur.Children = append(cur.Children, d)
} else {
directives = append(directives, d)
}
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("failed to read config file: %v", err)
}
return &Directive{Children: directives}, nil
}