// 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() }