ini-grinder/ini.go

99 lines
2.1 KiB
Go
Raw Normal View History

2022-12-20 18:04:39 +01:00
package ini
import (
"bufio"
"io"
"strings"
)
// Singular key-value pair under the given section within an INI file.
type Entry struct {
Section string
Key string
Value string
}
// Returns the last error that occured during parsing.
func (parser *Parser) Err() error {
return parser.err
}
// Creates and returns a new [Parser] by reference from `reader`
func NewParser(reader io.Reader) *Parser {
return &Parser{
scanner: bufio.NewScanner(reader),
}
}
// Parses the next key-value pair in the `parser` stream, returning the parsed [Entry], or an empty
// one if nothing was parsed, and a `bool` representing whether or not there is any further data
// available to parse.
//
// Note that the `parser` does not guarantee any parse order for key-value pairs extracted from the
// `parser` stream.
func (parser *Parser) Parse() (Entry, bool) {
for parser.scanner.Scan() {
var line = strings.TrimSpace(parser.scanner.Text())
var lineLen = len(line)
if lineLen == 0 {
// Skip empty lines.
continue
}
if (line[0] == '#') || (line[0] == ';') {
// Skip comment lines.
continue
}
var lineTail = lineLen - 1
if (line[0] == '[') && (line[lineTail] == ']') {
// Section name.
parser.section = line[1:lineTail]
continue
}
if assignmentIndex := strings.Index(line, "="); assignmentIndex > -1 {
// Key with value.
var value = strings.TrimSpace(line[assignmentIndex+1:])
var valueLen = len(value)
if valueLen != 0 {
var valueTail = len(value) - 1
if (value[0] == '"') && (value[valueTail] == '"') {
value = value[1:valueTail]
}
}
return Entry{
Section: parser.section,
Key: strings.TrimSpace(line[0:assignmentIndex]),
Value: value,
}, true
}
// Key which is its own value.
var keyValue = line[1:lineTail]
return Entry{
Section: parser.section,
Key: keyValue,
Value: keyValue,
}, true
}
parser.err = parser.scanner.Err()
return Entry{}, false
}
// State machine for parsing streamable INI file sources.
type Parser struct {
scanner *bufio.Scanner
err error
section string
}