-
Notifications
You must be signed in to change notification settings - Fork 1
/
ini.go
144 lines (119 loc) · 2.69 KB
/
ini.go
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
// Package ini allows to read ini files
package main
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)
type Config struct {
Path string
Sections []string
Values map[string]string
}
func NewConfig(path string) (*Config, error) {
c, err := Open(path)
if err != nil {
return nil, err
}
if c != nil {
c.Path = path
return c, nil
}
c = &Config{
Path: path,
Values: make(map[string]string),
}
return c, nil
}
// Get returns a configuration value.
func (c *Config) Get(keys ...string) string {
key := strings.Join(keys, ".")
return c.Values[key]
}
// Set assigns a configuration value
func (c *Config) Set(key, value string) {
c.Values[key] = value
}
// String returns the value if present or defaultValue
func (c *Config) String(key string, defaultValue string) string {
v, ok := c.Values[key]
if ok {
return v
}
return defaultValue
}
// Bool returns the value if present or defaultValue
func (c *Config) Bool(key string, defaultValue bool) bool {
v, ok := c.Values[key]
if ok {
return v == "true"
}
return defaultValue
}
// Int returns the value if present or defaultValue
func (c *Config) Int(key string, defaultValue int) int {
v, ok := c.Values[key]
if ok {
if i, err := strconv.Atoi(v); err == nil {
return i
}
}
return defaultValue
}
// File parses a ini file
func Open(f string) (*Config, error) {
b, err := ioutil.ReadFile(f)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
return Parse(string(b))
}
func (c *Config) Save() error {
var buf []byte
for k, v := range c.Values {
if strings.ContainsRune(k, '.') {
return fmt.Errorf("Section save is not implemented yet")
}
buf = append(buf, []byte(k+"="+v+"\n")...)
}
return ioutil.WriteFile(c.Path, buf, 0644)
}
// File parses a ini string
func Parse(s string) (*Config, error) {
var sections []string
values := make(map[string]string)
currentSection := ""
for l, line := range strings.Split(s, "\n") {
line = strings.Trim(line, " \t\r")
// ignore empty lines or comments
if len(line) == 0 || line[0] == '#' {
continue
}
// parse section
if line[0] == '[' {
if line[len(line)-1] != ']' {
return nil, fmt.Errorf("Unbound section in line %d: %s", l, line)
}
currentSection = line[1 : len(line)-1]
sections = append(sections, currentSection)
continue
}
// parse value
i := strings.Index(line, "=")
if i == -1 {
return nil, fmt.Errorf("Invalid value in line %d: %s", l, line)
}
key := strings.Trim(line[:i], " \t")
if currentSection != "" {
key = currentSection + "." + key
}
value := strings.Trim(line[i+1:], " \t")
values[key] = value
}
return &Config{Sections: sections, Values: values}, nil
}