nix-amer/internal/cnf/parser/nginx/decoder.go

116 lines
2.1 KiB
Go
Raw Normal View History

package nginx
import (
"bufio"
"fmt"
"io"
"regexp"
"strings"
)
var ErrNullReceiver = fmt.Errorf("decoder receiver must not be null")
var ErrInvalidReceiver = fmt.Errorf("decoder receiver must be compatible with *[]*Line")
// decoder implements parser.Decoder
type decoder struct{ reader io.Reader }
func (d *decoder) Decode(v interface{}) error {
// check 'v'
if v == nil {
return ErrNullReceiver
}
vcast, ok := v.(*[]*Line)
if !ok {
return ErrInvalidReceiver
}
r := bufio.NewReader(d.reader)
n := -1 // line number
// regexes
reSection := regexp.MustCompile(`(?m)^([a-z0-9_-]+)\s+\{$`)
reAssign := regexp.MustCompile(`(?m)^([a-z0-9_-]+)\s+([^;#]+);$`)
reInclude := regexp.MustCompile(`(?m)^include\s+([^;#]+);$`)
// actual section tree
// tree := []Line{}
for {
n++
l := &Line{Number: n, Type: NONE}
// 1. read line
notrim, err := r.ReadString('\n')
if err == io.EOF {
break
} else if err != nil {
return err
}
// 2. ignore empty
line := strings.Trim(notrim, " \t\r\n")
if len(line) < 1 {
continue
}
// 3. get indentation
firstChar := 0
for ; !in_array(" \t\r\n", notrim[firstChar:][0]); firstChar++ {
}
l.Indent = notrim[0:firstChar]
// 3. comment
if line[0] == '#' {
l.Type = COMMENT
l.Components = []string{strings.Trim(line[1:], " \t")}
} else if line[0] == ';' {
l.Type = COLONCOMMENT
l.Components = []string{strings.Trim(line[1:], " \t")}
}
// 4. section
if l.Type == NONE {
match := reSection.FindStringSubmatch(line)
if match != nil {
l.Type = SECTION
l.Components = match[1:]
}
}
// 5. include
if l.Type == NONE {
match := reInclude.FindStringSubmatch(line)
if match != nil {
l.Type = INCLUDE
l.Components = []string{match[1]}
}
}
// 6. assignment
if l.Type == NONE {
match := reAssign.FindStringSubmatch(line)
if match != nil {
l.Type = ASSIGNMENT
l.Components = match[1:]
}
}
*vcast = append(*vcast, l)
}
return nil
}
func in_array(haystack string, needle byte) bool {
for i, l := 0, len(haystack); i < l; i++ {
if haystack[i] == needle {
return true
}
}
return false
}