2020-09-08 10:11:32 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"fmt"
|
2020-09-08 15:13:39 +00:00
|
|
|
"io"
|
|
|
|
"os"
|
2020-09-08 10:11:32 +00:00
|
|
|
|
|
|
|
"github.com/google/shlex"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Directive struct {
|
2020-09-08 15:13:39 +00:00
|
|
|
Name string
|
|
|
|
Params []string
|
2020-09-08 10:11:32 +00:00
|
|
|
Children []*Directive
|
|
|
|
}
|
|
|
|
|
2020-09-08 15:13:39 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-09-09 09:00:00 +00:00
|
|
|
func Load(path string) (*Directive, error) {
|
2020-09-08 10:11:32 +00:00
|
|
|
f, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
return Parse(f)
|
|
|
|
}
|
|
|
|
|
2020-09-09 09:00:00 +00:00
|
|
|
func Parse(r io.Reader) (*Directive, error) {
|
2020-09-08 10:11:32 +00:00
|
|
|
scanner := bufio.NewScanner(r)
|
|
|
|
|
|
|
|
var directives []*Directive
|
|
|
|
var cur *Directive
|
|
|
|
for scanner.Scan() {
|
|
|
|
l := scanner.Text()
|
|
|
|
words, err := shlex.Split(l)
|
|
|
|
if err != nil {
|
2020-09-09 09:00:00 +00:00
|
|
|
return nil, fmt.Errorf("failed to parse config file: %v", err)
|
2020-09-08 10:11:32 +00:00
|
|
|
} else if len(words) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-09-08 15:13:39 +00:00
|
|
|
if len(words) == 1 && l[len(l)-1] == '}' {
|
2020-09-08 10:11:32 +00:00
|
|
|
if cur == nil {
|
|
|
|
return nil, fmt.Errorf("unexpected '}'")
|
|
|
|
}
|
|
|
|
cur = nil
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var d *Directive
|
2020-09-08 15:13:39 +00:00
|
|
|
if words[len(words)-1] == "{" && l[len(l)-1] == '{' {
|
|
|
|
words = words[:len(words)-1]
|
2020-09-09 11:05:00 +00:00
|
|
|
|
|
|
|
var name string
|
|
|
|
params := words
|
|
|
|
if len(words) > 0 {
|
|
|
|
name, params = words[0], words[1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
d = &Directive{Name: name, Params: params}
|
2020-09-08 10:11:32 +00:00
|
|
|
cur = d
|
|
|
|
directives = append(directives, d)
|
|
|
|
} else {
|
2020-09-08 15:13:39 +00:00
|
|
|
d = &Directive{Name: words[0], Params: words[1:]}
|
2020-09-08 10:11:32 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-09-09 09:00:00 +00:00
|
|
|
return &Directive{Children: directives}, nil
|
2020-09-08 10:11:32 +00:00
|
|
|
}
|