1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
// Package ini is a tiny dependency-free reader for the boring INI files lectio
// uses for config and calendar data: [sections] (including "a/b" subsections),
// "key = value" pairs (keys may be dotted, e.g. name.pl), and "#"/";" comments.
// It preserves order and never interprets values beyond trimming.
package ini
import (
"bufio"
"bytes"
"fmt"
"strings"
)
type Pair struct{ Key, Val string }
type Section struct {
Name string
Pairs []Pair
}
// Parse reads INI bytes into ordered sections. Pairs before the first [section]
// go into a leading section with an empty Name.
func Parse(data []byte) ([]Section, error) {
secs := []Section{{Name: ""}}
sc := bufio.NewScanner(bytes.NewReader(data))
sc.Buffer(make([]byte, 0, 64*1024), 1024*1024)
line := 0
for sc.Scan() {
line++
raw := stripComment(sc.Text())
s := strings.TrimSpace(raw)
if s == "" {
continue
}
if strings.HasPrefix(s, "[") {
if !strings.HasSuffix(s, "]") {
return nil, fmt.Errorf("ini: line %d: unclosed section header %q", line, s)
}
name := strings.TrimSpace(s[1 : len(s)-1])
secs = append(secs, Section{Name: name})
continue
}
eq := strings.IndexByte(s, '=')
if eq < 0 {
return nil, fmt.Errorf("ini: line %d: expected key = value, got %q", line, s)
}
key := strings.TrimSpace(s[:eq])
val := strings.TrimSpace(s[eq+1:])
cur := &secs[len(secs)-1]
cur.Pairs = append(cur.Pairs, Pair{key, val})
}
return secs, sc.Err()
}
// stripComment removes a trailing "#" or ";" comment (our values never contain
// an unescaped # or ;).
func stripComment(line string) string {
for i := 0; i < len(line); i++ {
if line[i] == '#' || line[i] == ';' {
return line[:i]
}
}
return line
}
// List splits a comma-separated value, trimming spaces and dropping empties.
func List(val string) []string {
var out []string
for _, p := range strings.Split(val, ",") {
if t := strings.TrimSpace(p); t != "" {
out = append(out, t)
}
}
return out
}
|