/* * Copyright (C) 2022 Brian Evans * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ 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)} }