-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtparse.go
More file actions
147 lines (135 loc) · 3.45 KB
/
tparse.go
File metadata and controls
147 lines (135 loc) · 3.45 KB
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Package tparse implements data structures and simple functions to parse toml like syntax
package tparse
import (
"errors"
"fmt"
"io"
"regexp"
"strings"
)
// Entries Type is used for containing the key value pairs
type Entries map[string]string
// Dict Type is used for containing the whole toml like data
type Dict map[string]Entries
// Find returns value for the given string from the entries data structure.
// If not found it returns an empty string and an error.
func (e Entries) Find(key string) (string, error) {
ret, ok := e[key]
if !ok {
return "", errors.New("No such entry found")
}
return ret, nil
}
// NewDict returns the pointer to a Dict instance after initializing it.
func NewDict() *Dict {
a := make(Dict, 0)
return &a
}
// Find returns Entries if found and an error if not for a given heading.
func (d Dict) Find(heading string) (Entries, error) {
ret, ok := d[heading]
if !ok {
return nil, errors.New("No such section found")
}
return ret, nil
}
// UnMarshal writes the data as a toml structured text in a io.Writer
func (d Dict) UnMarshal(w io.Writer) error {
for section, entries := range d {
_, err := fmt.Fprintf(w, "[%s]\n", section)
if err != nil {
return err
}
for key, val := range entries {
_, err := fmt.Fprintf(w, "%s = %s\n", key, val)
if err != nil {
return err
}
}
_, err = fmt.Fprint(w, "\n")
if err != nil {
return err
}
}
return nil
}
// Parse is used to parse the content and store it in the Dict variable.
func (d Dict) Parse(contents string) error {
lines := strings.Split(contents, "\n")
head := regexp.MustCompile("^\\s*\\[.*\\]\\s*$")
kval := regexp.MustCompile("^[^\\[].*=.*")
empty := regexp.MustCompile("^\\s*$")
currentHeader := "root"
multiline := false
tempValue := ""
tempKey := ""
for i, val := range lines {
if multiline {
tempValue += "\n" + val
d[currentHeader][tempKey] = tempValue
if strings.HasSuffix(strings.TrimSpace(val), "`") {
d[currentHeader][tempKey] = strings.Trim(strings.TrimSpace(tempValue), "`")
tempValue = ""
tempKey = ""
multiline = false
}
continue
}
switch true {
case kval.MatchString(val):
key, value := getKeyValPair(val)
if strings.HasPrefix(value, "`") {
multiline = true
tempValue = value
tempKey = key
}
if strings.HasSuffix(value, "`") && multiline {
multiline = false
tempValue = ""
tempKey = ""
}
d[currentHeader][key] = value
case head.MatchString(val):
currentHeader = getHeader(val)
d[currentHeader] = make(map[string]string, 0)
case empty.MatchString(val):
continue
default:
return errors.New(fmt.Sprintf("Illegal Character in line %d", i))
}
}
return nil
}
// getHeader is used to get the heading from the toml section header.
func getHeader(h string) string {
head := regexp.MustCompile("^\\s*\\[(?P<heading>.*)\\]\\s*$")
sxn := head.SubexpNames()
matches := head.FindStringSubmatch(h)
for i, val := range matches {
if sxn[i] != "heading" {
continue
}
return strings.TrimSpace(val)
}
return ""
}
// getKeyValPair is used to get key and value from the passed toml expression
func getKeyValPair(kv string) (string, string) {
arr := strings.Split(kv, "=")
if len(arr) == 1 {
return "", ""
}
key := arr[0]
value := ""
for j, val := range arr {
if j == 0 {
continue
}
value = value + val
if j != len(arr)-1 {
value += "="
}
}
value = strings.Trim(strings.TrimSpace(value), "\"")
return strings.TrimSpace(key), value
}