101 lines
2.8 KiB
Go
101 lines
2.8 KiB
Go
// 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"
|
|
"errors"
|
|
"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)
|
|
for scanner.Scan() {
|
|
l := strings.TrimRightFunc(stripComments(scanner.Text()), unicode.IsSpace)
|
|
|
|
// 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 errors.New("could not parse line: " + l)
|
|
}
|
|
}
|
|
}
|
|
return scanner.Err()
|
|
}
|