forked from robfig/config
-
Notifications
You must be signed in to change notification settings - Fork 14
/
read.go
102 lines (86 loc) · 2.86 KB
/
read.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
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"bufio"
"fmt"
"os"
"strings"
"unicode"
)
// _read is the base to read a file and get the configuration representation.
// That representation can be queried with GetString, etc.
func _read(fname string, c *Config) (*Config, error) {
file, err := os.Open(fname)
if err != nil {
return nil, err
}
if err = c.read(bufio.NewReader(file)); err != nil {
return nil, err
}
if err = file.Close(); err != nil {
return nil, err
}
return c, nil
}
// Read reads a configuration file and returns its representation.
// All arguments, except `fname`, are related to `New()`
func Read(fname string, comment, separator string, preSpace, postSpace bool) (*Config, error) {
return _read(fname, New(comment, separator, preSpace, postSpace))
}
// ReadDefault reads a configuration file and returns its representation.
// It uses values by default.
func ReadDefault(fname string) (*Config, error) {
return _read(fname, NewDefault())
}
// * * *
func (c *Config) read(buf *bufio.Reader) (err error) {
var section, option string
var scanner = bufio.NewScanner(buf)
lineNo := 0
for scanner.Scan() {
l := strings.TrimRightFunc(stripComments(scanner.Text()), unicode.IsSpace)
lineNo++
// Switch written for readability (not performance)
switch {
// Empty line and comments
case len(l) == 0, l[0] == '#', l[0] == ';':
continue
// New section. The [ must be at the start of the line
case l[0] == '[' && l[len(l)-1] == ']':
option = "" // reset multi-line value
section = strings.TrimSpace(l[1 : len(l)-1])
c.AddSection(section)
// Continuation of multi-line value
// starts with whitespace, we're in a section and working on an option
case section != "" && option != "" && (l[0] == ' ' || l[0] == '\t'):
prev, _ := c.RawString(section, option)
value := strings.TrimSpace(l)
c.AddOption(section, option, prev+"\n"+value)
// Other alternatives
default:
i := strings.IndexAny(l, "=:")
switch {
// Option and value
case i > 0 && l[0] != ' ' && l[0] != '\t': // found an =: and it's not a multiline continuation
option = strings.TrimSpace(l[0:i])
value := strings.TrimSpace(l[i+1:])
c.AddOption(section, option, value)
default:
return fmt.Errorf("could not parse line #%v: %v", lineNo, l)
}
}
}
return scanner.Err()
}