Bombabillo is a non-web client for the terminal, supporting Gopher, Gemini and much more. https://bombadillo.colorfield.space
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

112 lines
2.3 KiB

package config
import (
"fmt"
"io"
"strings"
)
//------------------------------------------------\\
// + + + T Y P E S + + + \\
//--------------------------------------------------\\
type Parser struct {
s *scanner
row int
buffer struct {
token Token
size int
}
}
type Config struct {
// Bookmarks gopher.Bookmarks
Bookmarks struct {
Titles, Links []string
}
Settings []KeyValue
Certs []KeyValue
}
type KeyValue struct {
Key string
Value string
}
//------------------------------------------------\\
// + + + R E C E I V E R S + + + \\
//--------------------------------------------------\\
func (p *Parser) scan() (current Token) {
if p.buffer.size != 0 {
p.buffer.size = 0
return p.buffer.token
}
current = p.s.scan()
p.buffer.token = current
return
}
func (p *Parser) parseKeyValue() (KeyValue, error) {
kv := KeyValue{}
t1 := p.scan()
kv.Key = strings.TrimSpace(t1.val)
if t := p.scan(); t.kind == TOK_VALUE {
kv.Value = strings.TrimSpace(t.val)
} else {
return kv, fmt.Errorf("Got non-value expected VALUE on row %d", p.row)
}
if t := p.scan(); t.kind != TOK_NEWLINE {
return kv, fmt.Errorf("Expected NEWLINE, got %q on row %d", t.kind, p.row)
}
return kv, nil
}
func (p *Parser) unscan() { p.buffer.size = 1 }
func (p *Parser) Parse() (Config, error) {
p.row = 1
section := ""
c := Config{}
for {
if t := p.scan(); t.kind == TOK_NEWLINE {
p.row++
} else if t.kind == TOK_SECTION {
section = strings.ToUpper(t.val)
} else if t.kind == TOK_EOF {
break
} else if t.kind == TOK_KEY {
p.unscan()
keyval, err := p.parseKeyValue()
if err != nil {
return Config{}, err
}
switch section {
case "BOOKMARKS":
c.Bookmarks.Titles = append(c.Bookmarks.Titles, keyval.Value)
c.Bookmarks.Links = append(c.Bookmarks.Links, keyval.Key)
case "CERTS":
c.Certs = append(c.Certs, keyval)
case "SETTINGS":
c.Settings = append(c.Settings, keyval)
}
} else if t.kind == TOK_ERROR {
return Config{}, fmt.Errorf("Error on row %d: %s", p.row, t.val)
}
}
return c, nil
}
//------------------------------------------------\\
// + + + F U N C T I O N S + + + \\
//--------------------------------------------------\\
func NewParser(r io.Reader) *Parser {
return &Parser{s: NewScanner(r)}
}